Merge branch 'master' of ctdb into 'master' of samba
[vlendec/samba-autobuild/.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 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 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->base_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 num_entries;
342         uint16 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 num_entries;
374         uint16 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         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->base_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 char *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, 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", (unsigned long)ret, fname));
720
721         if (ret == -1) {
722                 /* No attribute or not supported. */
723 #if defined(ENOATTR)
724                 if (errno != ENOATTR)
725                         DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
726 #else
727                 if (errno != ENOSYS)
728                         DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
729 #endif
730                 TALLOC_FREE(pai_buf);
731                 return NULL;
732         }
733
734         paiv = create_pai_val(pai_buf, ret);
735
736         if (paiv) {
737                 DEBUG(10,("load_inherited_info: ACL type 0x%x for file %s\n",
738                         (unsigned int)paiv->sd_type,
739                         fname));
740         }
741
742         TALLOC_FREE(pai_buf);
743         return paiv;
744 }
745
746 /****************************************************************************
747  Functions to manipulate the internal ACE format.
748 ****************************************************************************/
749
750 /****************************************************************************
751  Count a linked list of canonical ACE entries.
752 ****************************************************************************/
753
754 static size_t count_canon_ace_list( canon_ace *l_head )
755 {
756         size_t count = 0;
757         canon_ace *ace;
758
759         for (ace = l_head; ace; ace = ace->next)
760                 count++;
761
762         return count;
763 }
764
765 /****************************************************************************
766  Free a linked list of canonical ACE entries.
767 ****************************************************************************/
768
769 static void free_canon_ace_list( canon_ace *l_head )
770 {
771         canon_ace *list, *next;
772
773         for (list = l_head; list; list = next) {
774                 next = list->next;
775                 DLIST_REMOVE(l_head, list);
776                 TALLOC_FREE(list);
777         }
778 }
779
780 /****************************************************************************
781  Function to duplicate a canon_ace entry.
782 ****************************************************************************/
783
784 static canon_ace *dup_canon_ace( canon_ace *src_ace)
785 {
786         canon_ace *dst_ace = talloc(talloc_tos(), canon_ace);
787
788         if (dst_ace == NULL)
789                 return NULL;
790
791         *dst_ace = *src_ace;
792         dst_ace->prev = dst_ace->next = NULL;
793         return dst_ace;
794 }
795
796 /****************************************************************************
797  Print out a canon ace.
798 ****************************************************************************/
799
800 static void print_canon_ace(canon_ace *pace, int num)
801 {
802         dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" );
803         dbgtext( "SID = %s ", sid_string_dbg(&pace->trustee));
804         if (pace->owner_type == UID_ACE) {
805                 const char *u_name = uidtoname(pace->unix_ug.id);
806                 dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.id, u_name );
807         } else if (pace->owner_type == GID_ACE) {
808                 char *g_name = gidtoname(pace->unix_ug.id);
809                 dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.id, g_name );
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 static 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 static int map_acl_perms_to_permset(connection_struct *conn, 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 void create_file_sids(const SMB_STRUCT_STAT *psbuf, struct dom_sid *powner_sid, struct dom_sid *pgroup_sid)
917 {
918         uid_to_sid( powner_sid, psbuf->st_ex_uid );
919         gid_to_sid( pgroup_sid, psbuf->st_ex_gid );
920 }
921
922 /****************************************************************************
923  Merge aces with a common UID or GID - if both are allow or deny, OR the permissions together and
924  delete the second one. If the first is deny, mask the permissions off and delete the allow
925  if the permissions become zero, delete the deny if the permissions are non zero.
926 ****************************************************************************/
927
928 static void merge_aces( canon_ace **pp_list_head, bool dir_acl)
929 {
930         canon_ace *l_head = *pp_list_head;
931         canon_ace *curr_ace_outer;
932         canon_ace *curr_ace_outer_next;
933
934         /*
935          * First, merge allow entries with identical SIDs, and deny entries
936          * with identical SIDs.
937          */
938
939         for (curr_ace_outer = l_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
940                 canon_ace *curr_ace;
941                 canon_ace *curr_ace_next;
942
943                 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
944
945                 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
946                         bool can_merge = false;
947
948                         curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
949
950                         /* For file ACLs we can merge if the SIDs and ALLOW/DENY
951                          * types are the same. For directory acls we must also
952                          * ensure the POSIX ACL types are the same.
953                          *
954                          * For the IDMAP_BOTH case, we must not merge
955                          * the UID and GID ACE values for same SID
956                          */
957
958                         if (!dir_acl) {
959                                 can_merge = (curr_ace->unix_ug.id == curr_ace_outer->unix_ug.id &&
960                                              curr_ace->owner_type == curr_ace_outer->owner_type &&
961                                              (curr_ace->attr == curr_ace_outer->attr));
962                         } else {
963                                 can_merge = (curr_ace->unix_ug.id == curr_ace_outer->unix_ug.id &&
964                                              curr_ace->owner_type == curr_ace_outer->owner_type &&
965                                              (curr_ace->type == curr_ace_outer->type) &&
966                                              (curr_ace->attr == curr_ace_outer->attr));
967                         }
968
969                         if (can_merge) {
970                                 if( DEBUGLVL( 10 )) {
971                                         dbgtext("merge_aces: Merging ACE's\n");
972                                         print_canon_ace( curr_ace_outer, 0);
973                                         print_canon_ace( curr_ace, 0);
974                                 }
975
976                                 /* Merge two allow or two deny ACE's. */
977
978                                 /* Theoretically we shouldn't merge a dir ACE if
979                                  * one ACE has the CI flag set, and the other
980                                  * ACE has the OI flag set, but this is rare
981                                  * enough we can ignore it. */
982
983                                 curr_ace_outer->perms |= curr_ace->perms;
984                                 curr_ace_outer->ace_flags |= curr_ace->ace_flags;
985                                 DLIST_REMOVE(l_head, curr_ace);
986                                 TALLOC_FREE(curr_ace);
987                                 curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
988                         }
989                 }
990         }
991
992         /*
993          * Now go through and mask off allow permissions with deny permissions.
994          * We can delete either the allow or deny here as we know that each SID
995          * appears only once in the list.
996          */
997
998         for (curr_ace_outer = l_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
999                 canon_ace *curr_ace;
1000                 canon_ace *curr_ace_next;
1001
1002                 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
1003
1004                 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
1005
1006                         curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
1007
1008                         /*
1009                          * Subtract ACE's with different entries. Due to the ordering constraints
1010                          * we've put on the ACL, we know the deny must be the first one.
1011                          */
1012
1013                         if (curr_ace->unix_ug.id == curr_ace_outer->unix_ug.id &&
1014                             (curr_ace->owner_type == curr_ace_outer->owner_type) &&
1015                             (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
1016
1017                                 if( DEBUGLVL( 10 )) {
1018                                         dbgtext("merge_aces: Masking ACE's\n");
1019                                         print_canon_ace( curr_ace_outer, 0);
1020                                         print_canon_ace( curr_ace, 0);
1021                                 }
1022
1023                                 curr_ace->perms &= ~curr_ace_outer->perms;
1024
1025                                 if (curr_ace->perms == 0) {
1026
1027                                         /*
1028                                          * The deny overrides the allow. Remove the allow.
1029                                          */
1030
1031                                         DLIST_REMOVE(l_head, curr_ace);
1032                                         TALLOC_FREE(curr_ace);
1033                                         curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
1034
1035                                 } else {
1036
1037                                         /*
1038                                          * Even after removing permissions, there
1039                                          * are still allow permissions - delete the deny.
1040                                          * It is safe to delete the deny here,
1041                                          * as we are guarenteed by the deny first
1042                                          * ordering that all the deny entries for
1043                                          * this SID have already been merged into one
1044                                          * before we can get to an allow ace.
1045                                          */
1046
1047                                         DLIST_REMOVE(l_head, curr_ace_outer);
1048                                         TALLOC_FREE(curr_ace_outer);
1049                                         break;
1050                                 }
1051                         }
1052
1053                 } /* end for curr_ace */
1054         } /* end for curr_ace_outer */
1055
1056         /* We may have modified the list. */
1057
1058         *pp_list_head = l_head;
1059 }
1060
1061 /****************************************************************************
1062  Map canon_ace perms to permission bits NT.
1063  The attr element is not used here - we only process deny entries on set,
1064  not get. Deny entries are implicit on get with ace->perms = 0.
1065 ****************************************************************************/
1066
1067 uint32_t map_canon_ace_perms(int snum,
1068                                 enum security_ace_type *pacl_type,
1069                                 mode_t perms,
1070                                 bool directory_ace)
1071 {
1072         uint32_t nt_mask = 0;
1073
1074         *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
1075
1076         if (lp_acl_map_full_control(snum) && ((perms & ALL_ACE_PERMS) == ALL_ACE_PERMS)) {
1077                 if (directory_ace) {
1078                         nt_mask = UNIX_DIRECTORY_ACCESS_RWX;
1079                 } else {
1080                         nt_mask = (UNIX_ACCESS_RWX & ~DELETE_ACCESS);
1081                 }
1082         } else if ((perms & ALL_ACE_PERMS) == (mode_t)0) {
1083                 /*
1084                  * Windows NT refuses to display ACEs with no permissions in them (but
1085                  * they are perfectly legal with Windows 2000). If the ACE has empty
1086                  * permissions we cannot use 0, so we use the otherwise unused
1087                  * WRITE_OWNER permission, which we ignore when we set an ACL.
1088                  * We abstract this into a #define of UNIX_ACCESS_NONE to allow this
1089                  * to be changed in the future.
1090                  */
1091
1092                 nt_mask = 0;
1093         } else {
1094                 if (directory_ace) {
1095                         nt_mask |= ((perms & S_IRUSR) ? UNIX_DIRECTORY_ACCESS_R : 0 );
1096                         nt_mask |= ((perms & S_IWUSR) ? UNIX_DIRECTORY_ACCESS_W : 0 );
1097                         nt_mask |= ((perms & S_IXUSR) ? UNIX_DIRECTORY_ACCESS_X : 0 );
1098                 } else {
1099                         nt_mask |= ((perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
1100                         nt_mask |= ((perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
1101                         nt_mask |= ((perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
1102                 }
1103         }
1104
1105         if ((perms & S_IWUSR) && lp_dos_filemode(snum)) {
1106                 nt_mask |= (SEC_STD_WRITE_DAC|SEC_STD_WRITE_OWNER|DELETE_ACCESS);
1107         }
1108
1109         DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
1110                         (unsigned int)perms, (unsigned int)nt_mask ));
1111
1112         return nt_mask;
1113 }
1114
1115 /****************************************************************************
1116  Map NT perms to a UNIX mode_t.
1117 ****************************************************************************/
1118
1119 #define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA)
1120 #define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA)
1121 #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
1122
1123 static mode_t map_nt_perms( uint32 *mask, int type)
1124 {
1125         mode_t mode = 0;
1126
1127         switch(type) {
1128         case S_IRUSR:
1129                 if((*mask) & GENERIC_ALL_ACCESS)
1130                         mode = S_IRUSR|S_IWUSR|S_IXUSR;
1131                 else {
1132                         mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
1133                         mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
1134                         mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
1135                 }
1136                 break;
1137         case S_IRGRP:
1138                 if((*mask) & GENERIC_ALL_ACCESS)
1139                         mode = S_IRGRP|S_IWGRP|S_IXGRP;
1140                 else {
1141                         mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
1142                         mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
1143                         mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
1144                 }
1145                 break;
1146         case S_IROTH:
1147                 if((*mask) & GENERIC_ALL_ACCESS)
1148                         mode = S_IROTH|S_IWOTH|S_IXOTH;
1149                 else {
1150                         mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
1151                         mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
1152                         mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
1153                 }
1154                 break;
1155         }
1156
1157         return mode;
1158 }
1159
1160 /****************************************************************************
1161  Unpack a struct security_descriptor into a UNIX owner and group.
1162 ****************************************************************************/
1163
1164 NTSTATUS unpack_nt_owners(struct connection_struct *conn,
1165                         uid_t *puser, gid_t *pgrp,
1166                         uint32 security_info_sent, const struct
1167                         security_descriptor *psd)
1168 {
1169         struct dom_sid owner_sid;
1170         struct dom_sid grp_sid;
1171
1172         *puser = (uid_t)-1;
1173         *pgrp = (gid_t)-1;
1174
1175         if(security_info_sent == 0) {
1176                 DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
1177                 return NT_STATUS_OK;
1178         }
1179
1180         /*
1181          * Validate the owner and group SID's.
1182          */
1183
1184         memset(&owner_sid, '\0', sizeof(owner_sid));
1185         memset(&grp_sid, '\0', sizeof(grp_sid));
1186
1187         DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
1188
1189         /*
1190          * Don't immediately fail if the owner sid cannot be validated.
1191          * This may be a group chown only set.
1192          */
1193
1194         if (security_info_sent & SECINFO_OWNER) {
1195                 sid_copy(&owner_sid, psd->owner_sid);
1196                 if (!sid_to_uid(&owner_sid, puser)) {
1197                         if (lp_force_unknown_acl_user(SNUM(conn))) {
1198                                 /* this allows take ownership to work
1199                                  * reasonably */
1200                                 *puser = get_current_uid(conn);
1201                         } else {
1202                                 DEBUG(3,("unpack_nt_owners: unable to validate"
1203                                          " owner sid for %s\n",
1204                                          sid_string_dbg(&owner_sid)));
1205                                 return NT_STATUS_INVALID_OWNER;
1206                         }
1207                 }
1208                 DEBUG(3,("unpack_nt_owners: owner sid mapped to uid %u\n",
1209                          (unsigned int)*puser ));
1210         }
1211
1212         /*
1213          * Don't immediately fail if the group sid cannot be validated.
1214          * This may be an owner chown only set.
1215          */
1216
1217         if (security_info_sent & SECINFO_GROUP) {
1218                 sid_copy(&grp_sid, psd->group_sid);
1219                 if (!sid_to_gid( &grp_sid, pgrp)) {
1220                         if (lp_force_unknown_acl_user(SNUM(conn))) {
1221                                 /* this allows take group ownership to work
1222                                  * reasonably */
1223                                 *pgrp = get_current_gid(conn);
1224                         } else {
1225                                 DEBUG(3,("unpack_nt_owners: unable to validate"
1226                                          " group sid.\n"));
1227                                 return NT_STATUS_INVALID_OWNER;
1228                         }
1229                 }
1230                 DEBUG(3,("unpack_nt_owners: group sid mapped to gid %u\n",
1231                          (unsigned int)*pgrp));
1232         }
1233
1234         DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
1235
1236         return NT_STATUS_OK;
1237 }
1238
1239
1240 static void trim_ace_perms(canon_ace *pace)
1241 {
1242         pace->perms = pace->perms & (S_IXUSR|S_IWUSR|S_IRUSR);
1243 }
1244
1245 static void ensure_minimal_owner_ace_perms(const bool is_directory,
1246                                            canon_ace *pace)
1247 {
1248         pace->perms |= S_IRUSR;
1249         if (is_directory) {
1250                 pace->perms |= (S_IWUSR|S_IXUSR);
1251         }
1252 }
1253
1254 /****************************************************************************
1255  Check if a given uid/SID is in a group gid/SID. This is probably very
1256  expensive and will need optimisation. A *lot* of optimisation :-). JRA.
1257 ****************************************************************************/
1258
1259 static bool uid_entry_in_group(connection_struct *conn, canon_ace *uid_ace, canon_ace *group_ace )
1260 {
1261         /* "Everyone" always matches every uid. */
1262
1263         if (dom_sid_equal(&group_ace->trustee, &global_sid_World))
1264                 return True;
1265
1266         /*
1267          * if it's the current user, we already have the unix token
1268          * and don't need to do the complex user_in_group_sid() call
1269          */
1270         if (uid_ace->unix_ug.id == get_current_uid(conn)) {
1271                 const struct security_unix_token *curr_utok = NULL;
1272                 size_t i;
1273
1274                 if (group_ace->unix_ug.id == get_current_gid(conn)) {
1275                         return True;
1276                 }
1277
1278                 curr_utok = get_current_utok(conn);
1279                 for (i=0; i < curr_utok->ngroups; i++) {
1280                         if (group_ace->unix_ug.id == curr_utok->groups[i]) {
1281                                 return True;
1282                         }
1283                 }
1284         }
1285
1286         /*
1287          * user_in_group_sid() uses create_token_from_sid()
1288          * which creates an artificial NT token given just a username,
1289          * so this is not reliable for users from foreign domains
1290          * exported by winbindd!
1291          */
1292         return user_sid_in_group_sid(&uid_ace->trustee, &group_ace->trustee);
1293 }
1294
1295 /****************************************************************************
1296  A well formed POSIX file or default ACL has at least 3 entries, a
1297  SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
1298  In addition, the owner must always have at least read access.
1299  When using this call on get_acl, the pst struct is valid and contains
1300  the mode of the file.
1301 ****************************************************************************/
1302
1303 static bool ensure_canon_entry_valid_on_get(connection_struct *conn,
1304                                         canon_ace **pp_ace,
1305                                         const struct dom_sid *pfile_owner_sid,
1306                                         const struct dom_sid *pfile_grp_sid,
1307                                         const SMB_STRUCT_STAT *pst)
1308 {
1309         canon_ace *pace;
1310         bool got_user = false;
1311         bool got_group = false;
1312         bool got_other = false;
1313
1314         for (pace = *pp_ace; pace; pace = pace->next) {
1315                 if (pace->type == SMB_ACL_USER_OBJ) {
1316                         got_user = true;
1317                 } else if (pace->type == SMB_ACL_GROUP_OBJ) {
1318                         got_group = true;
1319                 } else if (pace->type == SMB_ACL_OTHER) {
1320                         got_other = true;
1321                 }
1322         }
1323
1324         if (!got_user) {
1325                 if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1326                         DEBUG(0,("malloc fail.\n"));
1327                         return false;
1328                 }
1329
1330                 ZERO_STRUCTP(pace);
1331                 pace->type = SMB_ACL_USER_OBJ;
1332                 pace->owner_type = UID_ACE;
1333                 pace->unix_ug.type = ID_TYPE_UID;
1334                 pace->unix_ug.id = pst->st_ex_uid;
1335                 pace->trustee = *pfile_owner_sid;
1336                 pace->attr = ALLOW_ACE;
1337                 pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRUSR, S_IWUSR, S_IXUSR);
1338                 DLIST_ADD(*pp_ace, pace);
1339         }
1340
1341         if (!got_group) {
1342                 if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1343                         DEBUG(0,("malloc fail.\n"));
1344                         return false;
1345                 }
1346
1347                 ZERO_STRUCTP(pace);
1348                 pace->type = SMB_ACL_GROUP_OBJ;
1349                 pace->owner_type = GID_ACE;
1350                 pace->unix_ug.type = ID_TYPE_GID;
1351                 pace->unix_ug.id = pst->st_ex_gid;
1352                 pace->trustee = *pfile_grp_sid;
1353                 pace->attr = ALLOW_ACE;
1354                 pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRGRP, S_IWGRP, S_IXGRP);
1355                 DLIST_ADD(*pp_ace, pace);
1356         }
1357
1358         if (!got_other) {
1359                 if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1360                         DEBUG(0,("malloc fail.\n"));
1361                         return false;
1362                 }
1363
1364                 ZERO_STRUCTP(pace);
1365                 pace->type = SMB_ACL_OTHER;
1366                 pace->owner_type = WORLD_ACE;
1367                 pace->unix_ug.type = ID_TYPE_NOT_SPECIFIED;
1368                 pace->unix_ug.id = -1;
1369                 pace->trustee = global_sid_World;
1370                 pace->attr = ALLOW_ACE;
1371                 pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IROTH, S_IWOTH, S_IXOTH);
1372                 DLIST_ADD(*pp_ace, pace);
1373         }
1374
1375         return true;
1376 }
1377
1378 /****************************************************************************
1379  A well formed POSIX file or default ACL has at least 3 entries, a
1380  SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
1381  In addition, the owner must always have at least read access.
1382  When using this call on set_acl, the pst struct has
1383  been modified to have a mode containing the default for this file or directory
1384  type.
1385 ****************************************************************************/
1386
1387 static bool ensure_canon_entry_valid_on_set(connection_struct *conn,
1388                                         canon_ace **pp_ace,
1389                                         bool is_default_acl,
1390                                         const struct share_params *params,
1391                                         const bool is_directory,
1392                                         const struct dom_sid *pfile_owner_sid,
1393                                         const struct dom_sid *pfile_grp_sid,
1394                                         const SMB_STRUCT_STAT *pst)
1395 {
1396         canon_ace *pace;
1397         canon_ace *pace_user = NULL;
1398         canon_ace *pace_group = NULL;
1399         canon_ace *pace_other = NULL;
1400         bool got_duplicate_user = false;
1401         bool got_duplicate_group = false;
1402
1403         for (pace = *pp_ace; pace; pace = pace->next) {
1404                 trim_ace_perms(pace);
1405                 if (pace->type == SMB_ACL_USER_OBJ) {
1406                         ensure_minimal_owner_ace_perms(is_directory, pace);
1407                         pace_user = pace;
1408                 } else if (pace->type == SMB_ACL_GROUP_OBJ) {
1409                         pace_group = pace;
1410                 } else if (pace->type == SMB_ACL_OTHER) {
1411                         pace_other = pace;
1412                 }
1413         }
1414
1415         if (!pace_user) {
1416                 canon_ace *pace_iter;
1417
1418                 if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1419                         DEBUG(0,("talloc fail.\n"));
1420                         return false;
1421                 }
1422
1423                 ZERO_STRUCTP(pace);
1424                 pace->type = SMB_ACL_USER_OBJ;
1425                 pace->owner_type = UID_ACE;
1426                 pace->unix_ug.type = ID_TYPE_UID;
1427                 pace->unix_ug.id = pst->st_ex_uid;
1428                 pace->trustee = *pfile_owner_sid;
1429                 pace->attr = ALLOW_ACE;
1430                 /* Start with existing user permissions, principle of least
1431                    surprises for the user. */
1432                 pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRUSR, S_IWUSR, S_IXUSR);
1433
1434                 /* See if the owning user is in any of the other groups in
1435                    the ACE, or if there's a matching user entry (by uid
1436                    or in the case of ID_TYPE_BOTH by SID).
1437                    If so, OR in the permissions from that entry. */
1438
1439
1440                 for (pace_iter = *pp_ace; pace_iter; pace_iter = pace_iter->next) {
1441                         if (pace_iter->type == SMB_ACL_USER &&
1442                                         pace_iter->unix_ug.id == pace->unix_ug.id) {
1443                                 pace->perms |= pace_iter->perms;
1444                         } else if (pace_iter->type == SMB_ACL_GROUP_OBJ || pace_iter->type == SMB_ACL_GROUP) {
1445                                 if (dom_sid_equal(&pace->trustee, &pace_iter->trustee)) {
1446                                         pace->perms |= pace_iter->perms;
1447                                 } else if (uid_entry_in_group(conn, pace, pace_iter)) {
1448                                         pace->perms |= pace_iter->perms;
1449                                 }
1450                         }
1451                 }
1452
1453                 if (pace->perms == 0) {
1454                         /* If we only got an "everyone" perm, just use that. */
1455                         if (pace_other)
1456                                 pace->perms = pace_other->perms;
1457                 }
1458
1459                 /*
1460                  * Ensure we have default parameters for the
1461                  * user (owner) even on default ACLs.
1462                  */
1463                 ensure_minimal_owner_ace_perms(is_directory, pace);
1464
1465                 DLIST_ADD(*pp_ace, pace);
1466                 pace_user = pace;
1467         }
1468
1469         if (!pace_group) {
1470                 if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1471                         DEBUG(0,("talloc fail.\n"));
1472                         return false;
1473                 }
1474
1475                 ZERO_STRUCTP(pace);
1476                 pace->type = SMB_ACL_GROUP_OBJ;
1477                 pace->owner_type = GID_ACE;
1478                 pace->unix_ug.type = ID_TYPE_GID;
1479                 pace->unix_ug.id = pst->st_ex_gid;
1480                 pace->trustee = *pfile_grp_sid;
1481                 pace->attr = ALLOW_ACE;
1482
1483                 /* If we only got an "everyone" perm, just use that. */
1484                 if (pace_other) {
1485                         pace->perms = pace_other->perms;
1486                 } else {
1487                         pace->perms = 0;
1488                 }
1489
1490                 DLIST_ADD(*pp_ace, pace);
1491                 pace_group = pace;
1492         }
1493
1494         if (!pace_other) {
1495                 if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1496                         DEBUG(0,("talloc fail.\n"));
1497                         return false;
1498                 }
1499
1500                 ZERO_STRUCTP(pace);
1501                 pace->type = SMB_ACL_OTHER;
1502                 pace->owner_type = WORLD_ACE;
1503                 pace->unix_ug.type = ID_TYPE_NOT_SPECIFIED;
1504                 pace->unix_ug.id = -1;
1505                 pace->trustee = global_sid_World;
1506                 pace->attr = ALLOW_ACE;
1507                 pace->perms = 0;
1508
1509                 DLIST_ADD(*pp_ace, pace);
1510                 pace_other = pace;
1511         }
1512
1513         /* Ensure when setting a POSIX ACL, that the uid for a
1514            SMB_ACL_USER_OBJ ACE (the owner ACE entry) has a duplicate
1515            permission entry as an SMB_ACL_USER, and a gid for a
1516            SMB_ACL_GROUP_OBJ ACE (the primary group ACE entry) also has
1517            a duplicate permission entry as an SMB_ACL_GROUP. If not,
1518            then if the ownership or group ownership of this file or
1519            directory gets changed, the user or group can lose their
1520            access. */
1521
1522         for (pace = *pp_ace; pace; pace = pace->next) {
1523                 if (pace->type == SMB_ACL_USER &&
1524                                 pace->unix_ug.id == pace_user->unix_ug.id) {
1525                         /* Already got one. */
1526                         got_duplicate_user = true;
1527                 } else if (pace->type == SMB_ACL_GROUP &&
1528                                 pace->unix_ug.id == pace_group->unix_ug.id) {
1529                         /* Already got one. */
1530                         got_duplicate_group = true;
1531                 } else if ((pace->type == SMB_ACL_GROUP)
1532                            && (dom_sid_equal(&pace->trustee, &pace_user->trustee))) {
1533                         /* If the SID owning the file appears
1534                          * in a group entry, then we have
1535                          * enough duplication, they will still
1536                          * have access */
1537                         got_duplicate_user = true;
1538                 }
1539         }
1540
1541         /* If the SID is equal for the user and group that we need
1542            to add the duplicate for, add only the group */
1543         if (!got_duplicate_user && !got_duplicate_group
1544                         && dom_sid_equal(&pace_group->trustee,
1545                                         &pace_user->trustee)) {
1546                 /* Add a duplicate SMB_ACL_GROUP entry, this
1547                  * will cover the owning SID as well, as it
1548                  * will always be mapped to both a uid and
1549                  * gid. */
1550
1551                 if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1552                         DEBUG(0,("talloc fail.\n"));
1553                         return false;
1554                 }
1555
1556                 ZERO_STRUCTP(pace);
1557                 pace->type = SMB_ACL_GROUP;;
1558                 pace->owner_type = GID_ACE;
1559                 pace->unix_ug.type = ID_TYPE_GID;
1560                 pace->unix_ug.id = pace_group->unix_ug.id;
1561                 pace->trustee = pace_group->trustee;
1562                 pace->attr = pace_group->attr;
1563                 pace->perms = pace_group->perms;
1564
1565                 DLIST_ADD(*pp_ace, pace);
1566
1567                 /* We're done here, make sure the
1568                    statements below are not executed. */
1569                 got_duplicate_user = true;
1570                 got_duplicate_group = true;
1571         }
1572
1573         if (!got_duplicate_user) {
1574                 /* Add a duplicate SMB_ACL_USER entry. */
1575                 if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1576                         DEBUG(0,("talloc fail.\n"));
1577                         return false;
1578                 }
1579
1580                 ZERO_STRUCTP(pace);
1581                 pace->type = SMB_ACL_USER;;
1582                 pace->owner_type = UID_ACE;
1583                 pace->unix_ug.type = ID_TYPE_UID;
1584                 pace->unix_ug.id = pace_user->unix_ug.id;
1585                 pace->trustee = pace_user->trustee;
1586                 pace->attr = pace_user->attr;
1587                 pace->perms = pace_user->perms;
1588
1589                 DLIST_ADD(*pp_ace, pace);
1590
1591                 got_duplicate_user = true;
1592         }
1593
1594         if (!got_duplicate_group) {
1595                 /* Add a duplicate SMB_ACL_GROUP entry. */
1596                 if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
1597                         DEBUG(0,("talloc fail.\n"));
1598                         return false;
1599                 }
1600
1601                 ZERO_STRUCTP(pace);
1602                 pace->type = SMB_ACL_GROUP;;
1603                 pace->owner_type = GID_ACE;
1604                 pace->unix_ug.type = ID_TYPE_GID;
1605                 pace->unix_ug.id = pace_group->unix_ug.id;
1606                 pace->trustee = pace_group->trustee;
1607                 pace->attr = pace_group->attr;
1608                 pace->perms = pace_group->perms;
1609
1610                 DLIST_ADD(*pp_ace, pace);
1611
1612                 got_duplicate_group = true;
1613         }
1614
1615         return true;
1616 }
1617
1618 /****************************************************************************
1619  Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries.
1620  If it does not have them, check if there are any entries where the trustee is the
1621  file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ.
1622  Note we must not do this to default directory ACLs.
1623 ****************************************************************************/
1624
1625 static void check_owning_objs(canon_ace *ace, struct dom_sid *pfile_owner_sid, struct dom_sid *pfile_grp_sid)
1626 {
1627         bool got_user_obj, got_group_obj;
1628         canon_ace *current_ace;
1629         int i, entries;
1630
1631         entries = count_canon_ace_list(ace);
1632         got_user_obj = False;
1633         got_group_obj = False;
1634
1635         for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1636                 if (current_ace->type == SMB_ACL_USER_OBJ)
1637                         got_user_obj = True;
1638                 else if (current_ace->type == SMB_ACL_GROUP_OBJ)
1639                         got_group_obj = True;
1640         }
1641         if (got_user_obj && got_group_obj) {
1642                 DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n"));
1643                 return;
1644         }
1645
1646         for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1647                 if (!got_user_obj && current_ace->owner_type == UID_ACE &&
1648                                 dom_sid_equal(&current_ace->trustee, pfile_owner_sid)) {
1649                         current_ace->type = SMB_ACL_USER_OBJ;
1650                         got_user_obj = True;
1651                 }
1652                 if (!got_group_obj && current_ace->owner_type == GID_ACE &&
1653                                 dom_sid_equal(&current_ace->trustee, pfile_grp_sid)) {
1654                         current_ace->type = SMB_ACL_GROUP_OBJ;
1655                         got_group_obj = True;
1656                 }
1657         }
1658         if (!got_user_obj)
1659                 DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n"));
1660         if (!got_group_obj)
1661                 DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
1662 }
1663
1664 static bool add_current_ace_to_acl(files_struct *fsp, struct security_ace *psa,
1665                                    canon_ace **file_ace, canon_ace **dir_ace,
1666                                    bool *got_file_allow, bool *got_dir_allow,
1667                                    bool *all_aces_are_inherit_only,
1668                                    canon_ace *current_ace)
1669 {
1670
1671         /*
1672          * Map the given NT permissions into a UNIX mode_t containing only
1673          * S_I(R|W|X)USR bits.
1674          */
1675
1676         current_ace->perms |= map_nt_perms( &psa->access_mask, S_IRUSR);
1677         current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
1678
1679         /* Store the ace_flag. */
1680         current_ace->ace_flags = psa->flags;
1681
1682         /*
1683          * Now add the created ace to either the file list, the directory
1684          * list, or both. We *MUST* preserve the order here (hence we use
1685          * DLIST_ADD_END) as NT ACLs are order dependent.
1686          */
1687
1688         if (fsp->is_directory) {
1689
1690                 /*
1691                  * We can only add to the default POSIX ACE list if the ACE is
1692                  * designed to be inherited by both files and directories.
1693                  */
1694
1695                 if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
1696                     (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
1697
1698                         canon_ace *current_dir_ace = current_ace;
1699                         DLIST_ADD_END(*dir_ace, current_ace, canon_ace *);
1700
1701                         /*
1702                          * Note if this was an allow ace. We can't process
1703                          * any further deny ace's after this.
1704                          */
1705
1706                         if (current_ace->attr == ALLOW_ACE)
1707                                 *got_dir_allow = True;
1708
1709                         if ((current_ace->attr == DENY_ACE) && *got_dir_allow) {
1710                                 DEBUG(0,("add_current_ace_to_acl: "
1711                                          "malformed ACL in "
1712                                          "inheritable ACL! Deny entry "
1713                                          "after Allow entry. Failing "
1714                                          "to set on file %s.\n",
1715                                          fsp_str_dbg(fsp)));
1716                                 return False;
1717                         }
1718
1719                         if( DEBUGLVL( 10 )) {
1720                                 dbgtext("add_current_ace_to_acl: adding dir ACL:\n");
1721                                 print_canon_ace( current_ace, 0);
1722                         }
1723
1724                         /*
1725                          * If this is not an inherit only ACE we need to add a duplicate
1726                          * to the file acl.
1727                          */
1728
1729                         if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1730                                 canon_ace *dup_ace = dup_canon_ace(current_ace);
1731
1732                                 if (!dup_ace) {
1733                                         DEBUG(0,("add_current_ace_to_acl: malloc fail !\n"));
1734                                         return False;
1735                                 }
1736
1737                                 /*
1738                                  * We must not free current_ace here as its
1739                                  * pointer is now owned by the dir_ace list.
1740                                  */
1741                                 current_ace = dup_ace;
1742                                 /* We've essentially split this ace into two,
1743                                  * and added the ace with inheritance request
1744                                  * bits to the directory ACL. Drop those bits for
1745                                  * the ACE we're adding to the file list. */
1746                                 current_ace->ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
1747                                                             SEC_ACE_FLAG_CONTAINER_INHERIT|
1748                                                             SEC_ACE_FLAG_INHERIT_ONLY);
1749                         } else {
1750                                 /*
1751                                  * We must not free current_ace here as its
1752                                  * pointer is now owned by the dir_ace list.
1753                                  */
1754                                 current_ace = NULL;
1755                         }
1756
1757                         /*
1758                          * current_ace is now either owned by file_ace
1759                          * or is NULL. We can safely operate on current_dir_ace
1760                          * to treat mapping for default acl entries differently
1761                          * than access acl entries.
1762                          */
1763
1764                         if (current_dir_ace->owner_type == UID_ACE) {
1765                                 /*
1766                                  * We already decided above this is a uid,
1767                                  * for default acls ace's only CREATOR_OWNER
1768                                  * maps to ACL_USER_OBJ. All other uid
1769                                  * ace's are ACL_USER.
1770                                  */
1771                                 if (dom_sid_equal(&current_dir_ace->trustee,
1772                                                   &global_sid_Creator_Owner)) {
1773                                         current_dir_ace->type = SMB_ACL_USER_OBJ;
1774                                 } else {
1775                                         current_dir_ace->type = SMB_ACL_USER;
1776                                 }
1777                         }
1778
1779                         if (current_dir_ace->owner_type == GID_ACE) {
1780                                 /*
1781                                  * We already decided above this is a gid,
1782                                  * for default acls ace's only CREATOR_GROUP
1783                                  * maps to ACL_GROUP_OBJ. All other uid
1784                                  * ace's are ACL_GROUP.
1785                                  */
1786                                 if (dom_sid_equal(&current_dir_ace->trustee,
1787                                                   &global_sid_Creator_Group)) {
1788                                         current_dir_ace->type = SMB_ACL_GROUP_OBJ;
1789                                 } else {
1790                                         current_dir_ace->type = SMB_ACL_GROUP;
1791                                 }
1792                         }
1793                 }
1794         }
1795
1796         /*
1797          * Only add to the file ACL if not inherit only.
1798          */
1799
1800         if (current_ace && !(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1801                 DLIST_ADD_END(*file_ace, current_ace, canon_ace *);
1802
1803                 /*
1804                  * Note if this was an allow ace. We can't process
1805                  * any further deny ace's after this.
1806                  */
1807
1808                 if (current_ace->attr == ALLOW_ACE)
1809                         *got_file_allow = True;
1810
1811                 if ((current_ace->attr == DENY_ACE) && *got_file_allow) {
1812                         DEBUG(0,("add_current_ace_to_acl: malformed "
1813                                  "ACL in file ACL ! Deny entry after "
1814                                  "Allow entry. Failing to set on file "
1815                                  "%s.\n", fsp_str_dbg(fsp)));
1816                         return False;
1817                 }
1818
1819                 if( DEBUGLVL( 10 )) {
1820                         dbgtext("add_current_ace_to_acl: adding file ACL:\n");
1821                         print_canon_ace( current_ace, 0);
1822                 }
1823                 *all_aces_are_inherit_only = False;
1824                 /*
1825                  * We must not free current_ace here as its
1826                  * pointer is now owned by the file_ace list.
1827                  */
1828                 current_ace = NULL;
1829         }
1830
1831         /*
1832          * Free if ACE was not added.
1833          */
1834
1835         TALLOC_FREE(current_ace);
1836         return true;
1837 }
1838
1839 /****************************************************************************
1840  Unpack a struct security_descriptor into two canonical ace lists.
1841 ****************************************************************************/
1842
1843 static bool create_canon_ace_lists(files_struct *fsp,
1844                                         const SMB_STRUCT_STAT *pst,
1845                                         struct dom_sid *pfile_owner_sid,
1846                                         struct dom_sid *pfile_grp_sid,
1847                                         canon_ace **ppfile_ace,
1848                                         canon_ace **ppdir_ace,
1849                                         const struct security_acl *dacl)
1850 {
1851         bool all_aces_are_inherit_only = (fsp->is_directory ? True : False);
1852         canon_ace *file_ace = NULL;
1853         canon_ace *dir_ace = NULL;
1854         canon_ace *current_ace = NULL;
1855         bool got_dir_allow = False;
1856         bool got_file_allow = False;
1857         int i, j;
1858
1859         *ppfile_ace = NULL;
1860         *ppdir_ace = NULL;
1861
1862         /*
1863          * Convert the incoming ACL into a more regular form.
1864          */
1865
1866         for(i = 0; i < dacl->num_aces; i++) {
1867                 struct security_ace *psa = &dacl->aces[i];
1868
1869                 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
1870                         DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
1871                         return False;
1872                 }
1873         }
1874
1875         /*
1876          * Deal with the fact that NT 4.x re-writes the canonical format
1877          * that we return for default ACLs. If a directory ACE is identical
1878          * to a inherited directory ACE then NT changes the bits so that the
1879          * first ACE is set to OI|IO and the second ACE for this SID is set
1880          * to CI. We need to repair this. JRA.
1881          */
1882
1883         for(i = 0; i < dacl->num_aces; i++) {
1884                 struct security_ace *psa1 = &dacl->aces[i];
1885
1886                 for (j = i + 1; j < dacl->num_aces; j++) {
1887                         struct security_ace *psa2 = &dacl->aces[j];
1888
1889                         if (psa1->access_mask != psa2->access_mask)
1890                                 continue;
1891
1892                         if (!dom_sid_equal(&psa1->trustee, &psa2->trustee))
1893                                 continue;
1894
1895                         /*
1896                          * Ok - permission bits and SIDs are equal.
1897                          * Check if flags were re-written.
1898                          */
1899
1900                         if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1901
1902                                 psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1903                                 psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1904
1905                         } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1906
1907                                 psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1908                                 psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1909
1910                         }
1911                 }
1912         }
1913
1914         for(i = 0; i < dacl->num_aces; i++) {
1915                 struct security_ace *psa = &dacl->aces[i];
1916
1917                 /*
1918                  * Create a canon_ace entry representing this NT DACL ACE.
1919                  */
1920
1921                 if ((current_ace = talloc(talloc_tos(), canon_ace)) == NULL) {
1922                         free_canon_ace_list(file_ace);
1923                         free_canon_ace_list(dir_ace);
1924                         DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
1925                         return False;
1926                 }
1927
1928                 ZERO_STRUCTP(current_ace);
1929
1930                 sid_copy(&current_ace->trustee, &psa->trustee);
1931
1932                 /*
1933                  * Try and work out if the SID is a user or group
1934                  * as we need to flag these differently for POSIX.
1935                  * Note what kind of a POSIX ACL this should map to.
1936                  */
1937
1938                 if( dom_sid_equal(&current_ace->trustee, &global_sid_World)) {
1939                         current_ace->owner_type = WORLD_ACE;
1940                         current_ace->unix_ug.type = ID_TYPE_NOT_SPECIFIED;
1941                         current_ace->unix_ug.id = -1;
1942                         current_ace->type = SMB_ACL_OTHER;
1943                 } else if (dom_sid_equal(&current_ace->trustee, &global_sid_Creator_Owner)) {
1944                         current_ace->owner_type = UID_ACE;
1945                         current_ace->unix_ug.type = ID_TYPE_UID;
1946                         current_ace->unix_ug.id = pst->st_ex_uid;
1947                         current_ace->type = SMB_ACL_USER_OBJ;
1948
1949                         /*
1950                          * The Creator Owner entry only specifies inheritable permissions,
1951                          * never access permissions. WinNT doesn't always set the ACE to
1952                          * INHERIT_ONLY, though.
1953                          */
1954
1955                         psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1956
1957                 } else if (dom_sid_equal(&current_ace->trustee, &global_sid_Creator_Group)) {
1958                         current_ace->owner_type = GID_ACE;
1959                         current_ace->unix_ug.type = ID_TYPE_GID;
1960                         current_ace->unix_ug.id = pst->st_ex_gid;
1961                         current_ace->type = SMB_ACL_GROUP_OBJ;
1962
1963                         /*
1964                          * The Creator Group entry only specifies inheritable permissions,
1965                          * never access permissions. WinNT doesn't always set the ACE to
1966                          * INHERIT_ONLY, though.
1967                          */
1968                         psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1969
1970                 } else {
1971                         struct unixid unixid;
1972
1973                         if (!sids_to_unixids(&current_ace->trustee, 1, &unixid)) {
1974                                 free_canon_ace_list(file_ace);
1975                                 free_canon_ace_list(dir_ace);
1976                                 TALLOC_FREE(current_ace);
1977                                 DEBUG(0, ("create_canon_ace_lists: sids_to_unixids "
1978                                         "failed for %s (allocation failure)\n",
1979                                         sid_string_dbg(&current_ace->trustee)));
1980                                 return false;
1981                         }
1982
1983                         if (unixid.type == ID_TYPE_BOTH) {
1984                                 /*
1985                                  * We must add both a user and group
1986                                  * entry POSIX_ACL.
1987                                  * This is due to the fact that in POSIX
1988                                  * user entries are more specific than
1989                                  * groups.
1990                                  */
1991                                 current_ace->owner_type = UID_ACE;
1992                                 current_ace->unix_ug.type = ID_TYPE_UID;
1993                                 current_ace->unix_ug.id = unixid.id;
1994                                 current_ace->type =
1995                                         (unixid.id == pst->st_ex_uid) ?
1996                                                 SMB_ACL_USER_OBJ :
1997                                                 SMB_ACL_USER;
1998
1999                                 /* Add the user object to the posix ACL,
2000                                    and proceed to the group mapping
2001                                    below. This handles the talloc_free
2002                                    of current_ace if not added for some
2003                                    reason */
2004                                 if (!add_current_ace_to_acl(fsp,
2005                                                 psa,
2006                                                 &file_ace,
2007                                                 &dir_ace,
2008                                                 &got_file_allow,
2009                                                 &got_dir_allow,
2010                                                 &all_aces_are_inherit_only,
2011                                                 current_ace)) {
2012                                         free_canon_ace_list(file_ace);
2013                                         free_canon_ace_list(dir_ace);
2014                                         return false;
2015                                 }
2016
2017                                 if ((current_ace = talloc(talloc_tos(),
2018                                                 canon_ace)) == NULL) {
2019                                         free_canon_ace_list(file_ace);
2020                                         free_canon_ace_list(dir_ace);
2021                                         DEBUG(0,("create_canon_ace_lists: "
2022                                                 "malloc fail.\n"));
2023                                         return False;
2024                                 }
2025
2026                                 ZERO_STRUCTP(current_ace);
2027
2028                                 sid_copy(&current_ace->trustee, &psa->trustee);
2029
2030                                 current_ace->unix_ug.type = ID_TYPE_GID;
2031                                 current_ace->unix_ug.id = unixid.id;
2032                                 current_ace->owner_type = GID_ACE;
2033                                 /* If it's the primary group, this is a
2034                                    group_obj, not a group. */
2035                                 if (current_ace->unix_ug.id == pst->st_ex_gid) {
2036                                         current_ace->type = SMB_ACL_GROUP_OBJ;
2037                                 } else {
2038                                         current_ace->type = SMB_ACL_GROUP;
2039                                 }
2040
2041                         } else if (unixid.type == ID_TYPE_UID) {
2042                                 current_ace->owner_type = UID_ACE;
2043                                 current_ace->unix_ug.type = ID_TYPE_UID;
2044                                 current_ace->unix_ug.id = unixid.id;
2045                                 /* If it's the owning user, this is a user_obj,
2046                                    not a user. */
2047                                 if (current_ace->unix_ug.id == pst->st_ex_uid) {
2048                                         current_ace->type = SMB_ACL_USER_OBJ;
2049                                 } else {
2050                                         current_ace->type = SMB_ACL_USER;
2051                                 }
2052                         } else if (unixid.type == ID_TYPE_GID) {
2053                                 current_ace->unix_ug.type = ID_TYPE_GID;
2054                                 current_ace->unix_ug.id = unixid.id;
2055                                 current_ace->owner_type = GID_ACE;
2056                                 /* If it's the primary group, this is a
2057                                    group_obj, not a group. */
2058                                 if (current_ace->unix_ug.id == pst->st_ex_gid) {
2059                                         current_ace->type = SMB_ACL_GROUP_OBJ;
2060                                 } else {
2061                                         current_ace->type = SMB_ACL_GROUP;
2062                                 }
2063                         } else {
2064                                 /*
2065                                  * Silently ignore map failures in non-mappable SIDs (NT Authority, BUILTIN etc).
2066                                  */
2067
2068                                 if (non_mappable_sid(&psa->trustee)) {
2069                                         DEBUG(10, ("create_canon_ace_lists: ignoring "
2070                                                    "non-mappable SID %s\n",
2071                                                    sid_string_dbg(&psa->trustee)));
2072                                         TALLOC_FREE(current_ace);
2073                                         continue;
2074                                 }
2075
2076                                 if (lp_force_unknown_acl_user(SNUM(fsp->conn))) {
2077                                         DEBUG(10, ("create_canon_ace_lists: ignoring "
2078                                                 "unknown or foreign SID %s\n",
2079                                                 sid_string_dbg(&psa->trustee)));
2080                                         TALLOC_FREE(current_ace);
2081                                         continue;
2082                                 }
2083
2084                                 free_canon_ace_list(file_ace);
2085                                 free_canon_ace_list(dir_ace);
2086                                 DEBUG(0, ("create_canon_ace_lists: unable to map SID "
2087                                           "%s to uid or gid.\n",
2088                                           sid_string_dbg(&current_ace->trustee)));
2089                                 TALLOC_FREE(current_ace);
2090                                 return false;
2091                         }
2092                 }
2093
2094                 /* handles the talloc_free of current_ace if not added for some reason */
2095                 if (!add_current_ace_to_acl(fsp, psa, &file_ace, &dir_ace,
2096                                             &got_file_allow, &got_dir_allow,
2097                                             &all_aces_are_inherit_only, current_ace)) {
2098                         free_canon_ace_list(file_ace);
2099                         free_canon_ace_list(dir_ace);
2100                         return false;
2101                 }
2102         }
2103
2104         if (fsp->is_directory && all_aces_are_inherit_only) {
2105                 /*
2106                  * Windows 2000 is doing one of these weird 'inherit acl'
2107                  * traverses to conserve NTFS ACL resources. Just pretend
2108                  * there was no DACL sent. JRA.
2109                  */
2110
2111                 DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));
2112                 free_canon_ace_list(file_ace);
2113                 free_canon_ace_list(dir_ace);
2114                 file_ace = NULL;
2115                 dir_ace = NULL;
2116         } else {
2117                 /*
2118                  * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in
2119                  * the file ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
2120                  * entries can be converted to *_OBJ. Don't do this for the default
2121                  * ACL, we will create them separately for this if needed inside
2122                  * ensure_canon_entry_valid_on_set().
2123                  */
2124                 if (file_ace) {
2125                         check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
2126                 }
2127         }
2128
2129         *ppfile_ace = file_ace;
2130         *ppdir_ace = dir_ace;
2131
2132         return True;
2133 }
2134
2135 /****************************************************************************
2136  ASCII art time again... JRA :-).
2137
2138  We have 4 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
2139  we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW
2140  entries). Secondly, the merge code has ensured that all duplicate SID entries for
2141  allow or deny have been merged, so the same SID can only appear once in the deny
2142  list or once in the allow list.
2143
2144  We then process as follows :
2145
2146  ---------------------------------------------------------------------------
2147  First pass - look for a Everyone DENY entry.
2148
2149  If it is deny all (rwx) trunate the list at this point.
2150  Else, walk the list from this point and use the deny permissions of this
2151  entry as a mask on all following allow entries. Finally, delete
2152  the Everyone DENY entry (we have applied it to everything possible).
2153
2154  In addition, in this pass we remove any DENY entries that have 
2155  no permissions (ie. they are a DENY nothing).
2156  ---------------------------------------------------------------------------
2157  Second pass - only deal with deny user entries.
2158
2159  DENY user1 (perms XXX)
2160
2161  new_perms = 0
2162  for all following allow group entries where user1 is in group
2163         new_perms |= group_perms;
2164
2165  user1 entry perms = new_perms & ~ XXX;
2166
2167  Convert the deny entry to an allow entry with the new perms and
2168  push to the end of the list. Note if the user was in no groups
2169  this maps to a specific allow nothing entry for this user.
2170
2171  The common case from the NT ACL choser (userX deny all) is
2172  optimised so we don't do the group lookup - we just map to
2173  an allow nothing entry.
2174
2175  What we're doing here is inferring the allow permissions the
2176  person setting the ACE on user1 wanted by looking at the allow
2177  permissions on the groups the user is currently in. This will
2178  be a snapshot, depending on group membership but is the best
2179  we can do and has the advantage of failing closed rather than
2180  open.
2181  ---------------------------------------------------------------------------
2182  Third pass - only deal with deny group entries.
2183
2184  DENY group1 (perms XXX)
2185
2186  for all following allow user entries where user is in group1
2187    user entry perms = user entry perms & ~ XXX;
2188
2189  If there is a group Everyone allow entry with permissions YYY,
2190  convert the group1 entry to an allow entry and modify its
2191  permissions to be :
2192
2193  new_perms = YYY & ~ XXX
2194
2195  and push to the end of the list.
2196
2197  If there is no group Everyone allow entry then convert the
2198  group1 entry to a allow nothing entry and push to the end of the list.
2199
2200  Note that the common case from the NT ACL choser (groupX deny all)
2201  cannot be optimised here as we need to modify user entries who are
2202  in the group to change them to a deny all also.
2203
2204  What we're doing here is modifying the allow permissions of
2205  user entries (which are more specific in POSIX ACLs) to mask
2206  out the explicit deny set on the group they are in. This will
2207  be a snapshot depending on current group membership but is the
2208  best we can do and has the advantage of failing closed rather
2209  than open.
2210  ---------------------------------------------------------------------------
2211  Fourth pass - cope with cumulative permissions.
2212
2213  for all allow user entries, if there exists an allow group entry with
2214  more permissive permissions, and the user is in that group, rewrite the
2215  allow user permissions to contain both sets of permissions.
2216
2217  Currently the code for this is #ifdef'ed out as these semantics make
2218  no sense to me. JRA.
2219  ---------------------------------------------------------------------------
2220
2221  Note we *MUST* do the deny user pass first as this will convert deny user
2222  entries into allow user entries which can then be processed by the deny
2223  group pass.
2224
2225  The above algorithm took a *lot* of thinking about - hence this
2226  explaination :-). JRA.
2227 ****************************************************************************/
2228
2229 /****************************************************************************
2230  Process a canon_ace list entries. This is very complex code. We need
2231  to go through and remove the "deny" permissions from any allow entry that matches
2232  the id of this entry. We have already refused any NT ACL that wasn't in correct
2233  order (DENY followed by ALLOW). If any allow entry ends up with zero permissions,
2234  we just remove it (to fail safe). We have already removed any duplicate ace
2235  entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all
2236  allow entries.
2237 ****************************************************************************/
2238
2239 static void process_deny_list(connection_struct *conn, canon_ace **pp_ace_list )
2240 {
2241         canon_ace *ace_list = *pp_ace_list;
2242         canon_ace *curr_ace = NULL;
2243         canon_ace *curr_ace_next = NULL;
2244
2245         /* Pass 1 above - look for an Everyone, deny entry. */
2246
2247         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
2248                 canon_ace *allow_ace_p;
2249
2250                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
2251
2252                 if (curr_ace->attr != DENY_ACE)
2253                         continue;
2254
2255                 if (curr_ace->perms == (mode_t)0) {
2256
2257                         /* Deny nothing entry - delete. */
2258
2259                         DLIST_REMOVE(ace_list, curr_ace);
2260                         continue;
2261                 }
2262
2263                 if (!dom_sid_equal(&curr_ace->trustee, &global_sid_World))
2264                         continue;
2265
2266                 /* JRATEST - assert. */
2267                 SMB_ASSERT(curr_ace->owner_type == WORLD_ACE);
2268
2269                 if (curr_ace->perms == ALL_ACE_PERMS) {
2270
2271                         /*
2272                          * Optimisation. This is a DENY_ALL to Everyone. Truncate the
2273                          * list at this point including this entry.
2274                          */
2275
2276                         canon_ace *prev_entry = DLIST_PREV(curr_ace);
2277
2278                         free_canon_ace_list( curr_ace );
2279                         if (prev_entry)
2280                                 DLIST_REMOVE(ace_list, prev_entry);
2281                         else {
2282                                 /* We deleted the entire list. */
2283                                 ace_list = NULL;
2284                         }
2285                         break;
2286                 }
2287
2288                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
2289
2290                         /* 
2291                          * Only mask off allow entries.
2292                          */
2293
2294                         if (allow_ace_p->attr != ALLOW_ACE)
2295                                 continue;
2296
2297                         allow_ace_p->perms &= ~curr_ace->perms;
2298                 }
2299
2300                 /*
2301                  * Now it's been applied, remove it.
2302                  */
2303
2304                 DLIST_REMOVE(ace_list, curr_ace);
2305         }
2306
2307         /* Pass 2 above - deal with deny user entries. */
2308
2309         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
2310                 mode_t new_perms = (mode_t)0;
2311                 canon_ace *allow_ace_p;
2312
2313                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
2314
2315                 if (curr_ace->attr != DENY_ACE)
2316                         continue;
2317
2318                 if (curr_ace->owner_type != UID_ACE)
2319                         continue;
2320
2321                 if (curr_ace->perms == ALL_ACE_PERMS) {
2322
2323                         /*
2324                          * Optimisation - this is a deny everything to this user.
2325                          * Convert to an allow nothing and push to the end of the list.
2326                          */
2327
2328                         curr_ace->attr = ALLOW_ACE;
2329                         curr_ace->perms = (mode_t)0;
2330                         DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
2331                         continue;
2332                 }
2333
2334                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
2335
2336                         if (allow_ace_p->attr != ALLOW_ACE)
2337                                 continue;
2338
2339                         /* We process GID_ACE and WORLD_ACE entries only. */
2340
2341                         if (allow_ace_p->owner_type == UID_ACE)
2342                                 continue;
2343
2344                         if (uid_entry_in_group(conn, curr_ace, allow_ace_p))
2345                                 new_perms |= allow_ace_p->perms;
2346                 }
2347
2348                 /*
2349                  * Convert to a allow entry, modify the perms and push to the end
2350                  * of the list.
2351                  */
2352
2353                 curr_ace->attr = ALLOW_ACE;
2354                 curr_ace->perms = (new_perms & ~curr_ace->perms);
2355                 DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
2356         }
2357
2358         /* Pass 3 above - deal with deny group entries. */
2359
2360         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
2361                 canon_ace *allow_ace_p;
2362                 canon_ace *allow_everyone_p = NULL;
2363
2364                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
2365
2366                 if (curr_ace->attr != DENY_ACE)
2367                         continue;
2368
2369                 if (curr_ace->owner_type != GID_ACE)
2370                         continue;
2371
2372                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
2373
2374                         if (allow_ace_p->attr != ALLOW_ACE)
2375                                 continue;
2376
2377                         /* Store a pointer to the Everyone allow, if it exists. */
2378                         if (allow_ace_p->owner_type == WORLD_ACE)
2379                                 allow_everyone_p = allow_ace_p;
2380
2381                         /* We process UID_ACE entries only. */
2382
2383                         if (allow_ace_p->owner_type != UID_ACE)
2384                                 continue;
2385
2386                         /* Mask off the deny group perms. */
2387
2388                         if (uid_entry_in_group(conn, allow_ace_p, curr_ace))
2389                                 allow_ace_p->perms &= ~curr_ace->perms;
2390                 }
2391
2392                 /*
2393                  * Convert the deny to an allow with the correct perms and
2394                  * push to the end of the list.
2395                  */
2396
2397                 curr_ace->attr = ALLOW_ACE;
2398                 if (allow_everyone_p)
2399                         curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms;
2400                 else
2401                         curr_ace->perms = (mode_t)0;
2402                 DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
2403         }
2404
2405         /* Doing this fourth pass allows Windows semantics to be layered
2406          * on top of POSIX semantics. I'm not sure if this is desirable.
2407          * For example, in W2K ACLs there is no way to say, "Group X no
2408          * access, user Y full access" if user Y is a member of group X.
2409          * This seems completely broken semantics to me.... JRA.
2410          */
2411
2412 #if 0
2413         /* Pass 4 above - deal with allow entries. */
2414
2415         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
2416                 canon_ace *allow_ace_p;
2417
2418                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
2419
2420                 if (curr_ace->attr != ALLOW_ACE)
2421                         continue;
2422
2423                 if (curr_ace->owner_type != UID_ACE)
2424                         continue;
2425
2426                 for (allow_ace_p = ace_list; allow_ace_p; allow_ace_p = allow_ace_p->next) {
2427
2428                         if (allow_ace_p->attr != ALLOW_ACE)
2429                                 continue;
2430
2431                         /* We process GID_ACE entries only. */
2432
2433                         if (allow_ace_p->owner_type != GID_ACE)
2434                                 continue;
2435
2436                         /* OR in the group perms. */
2437
2438                         if (uid_entry_in_group(conn, curr_ace, allow_ace_p))
2439                                 curr_ace->perms |= allow_ace_p->perms;
2440                 }
2441         }
2442 #endif
2443
2444         *pp_ace_list = ace_list;
2445 }
2446
2447 /****************************************************************************
2448  Unpack a struct security_descriptor into two canonical ace lists. We don't depend on this
2449  succeeding.
2450 ****************************************************************************/
2451
2452 static bool unpack_canon_ace(files_struct *fsp,
2453                                 const SMB_STRUCT_STAT *pst,
2454                                 struct dom_sid *pfile_owner_sid,
2455                                 struct dom_sid *pfile_grp_sid,
2456                                 canon_ace **ppfile_ace,
2457                                 canon_ace **ppdir_ace,
2458                                 uint32 security_info_sent,
2459                                 const struct security_descriptor *psd)
2460 {
2461         canon_ace *file_ace = NULL;
2462         canon_ace *dir_ace = NULL;
2463
2464         *ppfile_ace = NULL;
2465         *ppdir_ace = NULL;
2466
2467         if(security_info_sent == 0) {
2468                 DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
2469                 return False;
2470         }
2471
2472         /*
2473          * If no DACL then this is a chown only security descriptor.
2474          */
2475
2476         if(!(security_info_sent & SECINFO_DACL) || !psd->dacl)
2477                 return True;
2478
2479         /*
2480          * Now go through the DACL and create the canon_ace lists.
2481          */
2482
2483         if (!create_canon_ace_lists( fsp, pst, pfile_owner_sid, pfile_grp_sid,
2484                                                                 &file_ace, &dir_ace, psd->dacl))
2485                 return False;
2486
2487         if ((file_ace == NULL) && (dir_ace == NULL)) {
2488                 /* W2K traverse DACL set - ignore. */
2489                 return True;
2490         }
2491
2492         /*
2493          * Go through the canon_ace list and merge entries
2494          * belonging to identical users of identical allow or deny type.
2495          * We can do this as all deny entries come first, followed by
2496          * all allow entries (we have mandated this before accepting this acl).
2497          */
2498
2499         print_canon_ace_list( "file ace - before merge", file_ace);
2500         merge_aces( &file_ace, false);
2501
2502         print_canon_ace_list( "dir ace - before merge", dir_ace);
2503         merge_aces( &dir_ace, true);
2504
2505         /*
2506          * NT ACLs are order dependent. Go through the acl lists and
2507          * process DENY entries by masking the allow entries.
2508          */
2509
2510         print_canon_ace_list( "file ace - before deny", file_ace);
2511         process_deny_list(fsp->conn, &file_ace);
2512
2513         print_canon_ace_list( "dir ace - before deny", dir_ace);
2514         process_deny_list(fsp->conn, &dir_ace);
2515
2516         /*
2517          * A well formed POSIX file or default ACL has at least 3 entries, a 
2518          * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
2519          * and optionally a mask entry. Ensure this is the case.
2520          */
2521
2522         print_canon_ace_list( "file ace - before valid", file_ace);
2523
2524         if (!ensure_canon_entry_valid_on_set(fsp->conn, &file_ace, false, fsp->conn->params,
2525                         fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst)) {
2526                 free_canon_ace_list(file_ace);
2527                 free_canon_ace_list(dir_ace);
2528                 return False;
2529         }
2530
2531         print_canon_ace_list( "dir ace - before valid", dir_ace);
2532
2533         if (dir_ace && !ensure_canon_entry_valid_on_set(fsp->conn, &dir_ace, true, fsp->conn->params,
2534                         fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst)) {
2535                 free_canon_ace_list(file_ace);
2536                 free_canon_ace_list(dir_ace);
2537                 return False;
2538         }
2539
2540         print_canon_ace_list( "file ace - return", file_ace);
2541         print_canon_ace_list( "dir ace - return", dir_ace);
2542
2543         *ppfile_ace = file_ace;
2544         *ppdir_ace = dir_ace;
2545         return True;
2546
2547 }
2548
2549 /******************************************************************************
2550  When returning permissions, try and fit NT display
2551  semantics if possible. Note the the canon_entries here must have been malloced.
2552  The list format should be - first entry = owner, followed by group and other user
2553  entries, last entry = other.
2554
2555  Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
2556  are not ordered, and match on the most specific entry rather than walking a list,
2557  then a simple POSIX permission of rw-r--r-- should really map to 5 entries,
2558
2559  Entry 0: owner : deny all except read and write.
2560  Entry 1: owner : allow read and write.
2561  Entry 2: group : deny all except read.
2562  Entry 3: group : allow read.
2563  Entry 4: Everyone : allow read.
2564
2565  But NT cannot display this in their ACL editor !
2566 ********************************************************************************/
2567
2568 static void arrange_posix_perms(const char *filename, canon_ace **pp_list_head)
2569 {
2570         canon_ace *l_head = *pp_list_head;
2571         canon_ace *owner_ace = NULL;
2572         canon_ace *other_ace = NULL;
2573         canon_ace *ace = NULL;
2574
2575         for (ace = l_head; ace; ace = ace->next) {
2576                 if (ace->type == SMB_ACL_USER_OBJ)
2577                         owner_ace = ace;
2578                 else if (ace->type == SMB_ACL_OTHER) {
2579                         /* Last ace - this is "other" */
2580                         other_ace = ace;
2581                 }
2582         }
2583
2584         if (!owner_ace || !other_ace) {
2585                 DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n",
2586                         filename ));
2587                 return;
2588         }
2589
2590         /*
2591          * The POSIX algorithm applies to owner first, and other last,
2592          * so ensure they are arranged in this order.
2593          */
2594
2595         if (owner_ace) {
2596                 DLIST_PROMOTE(l_head, owner_ace);
2597         }
2598
2599         if (other_ace) {
2600                 DLIST_DEMOTE(l_head, other_ace, canon_ace *);
2601         }
2602
2603         /* We have probably changed the head of the list. */
2604
2605         *pp_list_head = l_head;
2606 }
2607
2608 /****************************************************************************
2609  Create a linked list of canonical ACE entries.
2610 ****************************************************************************/
2611
2612 static canon_ace *canonicalise_acl(struct connection_struct *conn,
2613                                    const char *fname, SMB_ACL_T posix_acl,
2614                                    const SMB_STRUCT_STAT *psbuf,
2615                                    const struct dom_sid *powner, const struct dom_sid *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
2616 {
2617         mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
2618         canon_ace *l_head = NULL;
2619         canon_ace *ace = NULL;
2620         canon_ace *next_ace = NULL;
2621         int entry_id = SMB_ACL_FIRST_ENTRY;
2622         bool is_default_acl = (the_acl_type == SMB_ACL_TYPE_DEFAULT);
2623         SMB_ACL_ENTRY_T entry;
2624         size_t ace_count;
2625
2626         while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
2627                 SMB_ACL_TAG_T tagtype;
2628                 SMB_ACL_PERMSET_T permset;
2629                 struct dom_sid sid;
2630                 struct unixid unix_ug;
2631                 enum ace_owner owner_type;
2632
2633                 entry_id = SMB_ACL_NEXT_ENTRY;
2634
2635                 /* Is this a MASK entry ? */
2636                 if (sys_acl_get_tag_type(entry, &tagtype) == -1)
2637                         continue;
2638
2639                 if (sys_acl_get_permset(entry, &permset) == -1)
2640                         continue;
2641
2642                 /* Decide which SID to use based on the ACL type. */
2643                 switch(tagtype) {
2644                         case SMB_ACL_USER_OBJ:
2645                                 /* Get the SID from the owner. */
2646                                 sid_copy(&sid, powner);
2647                                 unix_ug.type = ID_TYPE_UID;
2648                                 unix_ug.id = psbuf->st_ex_uid;
2649                                 owner_type = UID_ACE;
2650                                 break;
2651                         case SMB_ACL_USER:
2652                                 {
2653                                         uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
2654                                         if (puid == NULL) {
2655                                                 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
2656                                                 continue;
2657                                         }
2658                                         uid_to_sid( &sid, *puid);
2659                                         unix_ug.type = ID_TYPE_UID;
2660                                         unix_ug.id = *puid;
2661                                         owner_type = UID_ACE;
2662                                         break;
2663                                 }
2664                         case SMB_ACL_GROUP_OBJ:
2665                                 /* Get the SID from the owning group. */
2666                                 sid_copy(&sid, pgroup);
2667                                 unix_ug.type = ID_TYPE_GID;
2668                                 unix_ug.id = psbuf->st_ex_gid;
2669                                 owner_type = GID_ACE;
2670                                 break;
2671                         case SMB_ACL_GROUP:
2672                                 {
2673                                         gid_t *pgid = (gid_t *)sys_acl_get_qualifier(entry);
2674                                         if (pgid == NULL) {
2675                                                 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
2676                                                 continue;
2677                                         }
2678                                         gid_to_sid( &sid, *pgid);
2679                                         unix_ug.type = ID_TYPE_GID;
2680                                         unix_ug.id = *pgid;
2681                                         owner_type = GID_ACE;
2682                                         break;
2683                                 }
2684                         case SMB_ACL_MASK:
2685                                 acl_mask = convert_permset_to_mode_t(permset);
2686                                 continue; /* Don't count the mask as an entry. */
2687                         case SMB_ACL_OTHER:
2688                                 /* Use the Everyone SID */
2689                                 sid = global_sid_World;
2690                                 unix_ug.type = ID_TYPE_NOT_SPECIFIED;
2691                                 unix_ug.id = -1;
2692                                 owner_type = WORLD_ACE;
2693                                 break;
2694                         default:
2695                                 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
2696                                 continue;
2697                 }
2698
2699                 /*
2700                  * Add this entry to the list.
2701                  */
2702
2703                 if ((ace = talloc(talloc_tos(), canon_ace)) == NULL)
2704                         goto fail;
2705
2706                 ZERO_STRUCTP(ace);
2707                 ace->type = tagtype;
2708                 ace->perms = convert_permset_to_mode_t(permset);
2709                 ace->attr = ALLOW_ACE;
2710                 ace->trustee = sid;
2711                 ace->unix_ug = unix_ug;
2712                 ace->owner_type = owner_type;
2713                 ace->ace_flags = get_pai_flags(pal, ace, is_default_acl);
2714
2715                 DLIST_ADD(l_head, ace);
2716         }
2717
2718         /*
2719          * This next call will ensure we have at least a user/group/world set.
2720          */
2721
2722         if (!ensure_canon_entry_valid_on_get(conn, &l_head,
2723                                       powner, pgroup,
2724                                       psbuf))
2725                 goto fail;
2726
2727         /*
2728          * Now go through the list, masking the permissions with the
2729          * acl_mask. Ensure all DENY Entries are at the start of the list.
2730          */
2731
2732         DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", is_default_acl ?  "Default" : "Access"));
2733
2734         for ( ace_count = 0, ace = l_head; ace; ace = next_ace, ace_count++) {
2735                 next_ace = ace->next;
2736
2737                 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
2738                 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
2739                         ace->perms &= acl_mask;
2740
2741                 if (ace->perms == 0) {
2742                         DLIST_PROMOTE(l_head, ace);
2743                 }
2744
2745                 if( DEBUGLVL( 10 ) ) {
2746                         print_canon_ace(ace, ace_count);
2747                 }
2748         }
2749
2750         arrange_posix_perms(fname,&l_head );
2751
2752         print_canon_ace_list( "canonicalise_acl: ace entries after arrange", l_head );
2753
2754         return l_head;
2755
2756   fail:
2757
2758         free_canon_ace_list(l_head);
2759         return NULL;
2760 }
2761
2762 /****************************************************************************
2763  Check if the current user group list contains a given group.
2764 ****************************************************************************/
2765
2766 bool current_user_in_group(connection_struct *conn, gid_t gid)
2767 {
2768         int i;
2769         const struct security_unix_token *utok = get_current_utok(conn);
2770
2771         for (i = 0; i < utok->ngroups; i++) {
2772                 if (utok->groups[i] == gid) {
2773                         return True;
2774                 }
2775         }
2776
2777         return False;
2778 }
2779
2780 /****************************************************************************
2781  Should we override a deny ? Check 'acl group control' and 'dos filemode'.
2782 ****************************************************************************/
2783
2784 static bool acl_group_override(connection_struct *conn,
2785                                const struct smb_filename *smb_fname)
2786 {
2787         if ((errno != EPERM) && (errno != EACCES)) {
2788                 return false;
2789         }
2790
2791         /* file primary group == user primary or supplementary group */
2792         if (lp_acl_group_control(SNUM(conn)) &&
2793             current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
2794                 return true;
2795         }
2796
2797         /* user has writeable permission */
2798         if (lp_dos_filemode(SNUM(conn)) &&
2799             can_write_to_file(conn, smb_fname)) {
2800                 return true;
2801         }
2802
2803         return false;
2804 }
2805
2806 /****************************************************************************
2807  Attempt to apply an ACL to a file or directory.
2808 ****************************************************************************/
2809
2810 static bool set_canon_ace_list(files_struct *fsp,
2811                                 canon_ace *the_ace,
2812                                 bool default_ace,
2813                                 const SMB_STRUCT_STAT *psbuf,
2814                                 bool *pacl_set_support)
2815 {
2816         connection_struct *conn = fsp->conn;
2817         bool ret = False;
2818         SMB_ACL_T the_acl = sys_acl_init(talloc_tos());
2819         canon_ace *p_ace;
2820         int i;
2821         SMB_ACL_ENTRY_T mask_entry;
2822         bool got_mask_entry = False;
2823         SMB_ACL_PERMSET_T mask_permset;
2824         SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
2825         bool needs_mask = False;
2826         mode_t mask_perms = 0;
2827
2828         /* Use the psbuf that was passed in. */
2829         if (psbuf != &fsp->fsp_name->st) {
2830                 fsp->fsp_name->st = *psbuf;
2831         }
2832
2833 #if defined(POSIX_ACL_NEEDS_MASK)
2834         /* HP-UX always wants to have a mask (called "class" there). */
2835         needs_mask = True;
2836 #endif
2837
2838         if (the_acl == NULL) {
2839                 DEBUG(0, ("sys_acl_init failed to allocate an ACL\n"));
2840                 return false;
2841         }
2842
2843         if( DEBUGLVL( 10 )) {
2844                 dbgtext("set_canon_ace_list: setting ACL:\n");
2845                 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2846                         print_canon_ace( p_ace, i);
2847                 }
2848         }
2849
2850         for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2851                 SMB_ACL_ENTRY_T the_entry;
2852                 SMB_ACL_PERMSET_T the_permset;
2853
2854                 /*
2855                  * ACLs only "need" an ACL_MASK entry if there are any named user or
2856                  * named group entries. But if there is an ACL_MASK entry, it applies
2857                  * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask
2858                  * so that it doesn't deny (i.e., mask off) any permissions.
2859                  */
2860
2861                 if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) {
2862                         needs_mask = True;
2863                         mask_perms |= p_ace->perms;
2864                 } else if (p_ace->type == SMB_ACL_GROUP_OBJ) {
2865                         mask_perms |= p_ace->perms;
2866                 }
2867
2868                 /*
2869                  * Get the entry for this ACE.
2870                  */
2871
2872                 if (sys_acl_create_entry(&the_acl, &the_entry) == -1) {
2873                         DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
2874                                 i, strerror(errno) ));
2875                         goto fail;
2876                 }
2877
2878                 if (p_ace->type == SMB_ACL_MASK) {
2879                         mask_entry = the_entry;
2880                         got_mask_entry = True;
2881                 }
2882
2883                 /*
2884                  * Ok - we now know the ACL calls should be working, don't
2885                  * allow fallback to chmod.
2886                  */
2887
2888                 *pacl_set_support = True;
2889
2890                 /*
2891                  * Initialise the entry from the canon_ace.
2892                  */
2893
2894                 /*
2895                  * First tell the entry what type of ACE this is.
2896                  */
2897
2898                 if (sys_acl_set_tag_type(the_entry, p_ace->type) == -1) {
2899                         DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
2900                                 i, strerror(errno) ));
2901                         goto fail;
2902                 }
2903
2904                 /*
2905                  * Only set the qualifier (user or group id) if the entry is a user
2906                  * or group id ACE.
2907                  */
2908
2909                 if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
2910                         if (sys_acl_set_qualifier(the_entry,(void *)&p_ace->unix_ug.id) == -1) {
2911                                 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
2912                                         i, strerror(errno) ));
2913                                 goto fail;
2914                         }
2915                 }
2916
2917                 /*
2918                  * Convert the mode_t perms in the canon_ace to a POSIX permset.
2919                  */
2920
2921                 if (sys_acl_get_permset(the_entry, &the_permset) == -1) {
2922                         DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
2923                                 i, strerror(errno) ));
2924                         goto fail;
2925                 }
2926
2927                 if (map_acl_perms_to_permset(conn, p_ace->perms, &the_permset) == -1) {
2928                         DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
2929                                 (unsigned int)p_ace->perms, i, strerror(errno) ));
2930                         goto fail;
2931                 }
2932
2933                 /*
2934                  * ..and apply them to the entry.
2935                  */
2936
2937                 if (sys_acl_set_permset(the_entry, the_permset) == -1) {
2938                         DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
2939                                 i, strerror(errno) ));
2940                         goto fail;
2941                 }
2942
2943                 if( DEBUGLVL( 10 ))
2944                         print_canon_ace( p_ace, i);
2945
2946         }
2947
2948         if (needs_mask && !got_mask_entry) {
2949                 if (sys_acl_create_entry(&the_acl, &mask_entry) == -1) {
2950                         DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
2951                         goto fail;
2952                 }
2953
2954                 if (sys_acl_set_tag_type(mask_entry, SMB_ACL_MASK) == -1) {
2955                         DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
2956                         goto fail;
2957                 }
2958
2959                 if (sys_acl_get_permset(mask_entry, &mask_permset) == -1) {
2960                         DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
2961                         goto fail;
2962                 }
2963
2964                 if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
2965                         DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
2966                         goto fail;
2967                 }
2968
2969                 if (sys_acl_set_permset(mask_entry, mask_permset) == -1) {
2970                         DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
2971                         goto fail;
2972                 }
2973         }
2974
2975         /*
2976          * Finally apply it to the file or directory.
2977          */
2978
2979         if(default_ace || fsp->is_directory || fsp->fh->fd == -1) {
2980                 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name->base_name,
2981                                              the_acl_type, the_acl) == -1) {
2982                         /*
2983                          * Some systems allow all the above calls and only fail with no ACL support
2984                          * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2985                          */
2986                         if (no_acl_syscall_error(errno)) {
2987                                 *pacl_set_support = False;
2988                         }
2989
2990                         if (acl_group_override(conn, fsp->fsp_name)) {
2991                                 int sret;
2992
2993                                 DEBUG(5,("set_canon_ace_list: acl group "
2994                                          "control on and current user in file "
2995                                          "%s primary group.\n",
2996                                          fsp_str_dbg(fsp)));
2997
2998                                 become_root();
2999                                 sret = SMB_VFS_SYS_ACL_SET_FILE(conn,
3000                                     fsp->fsp_name->base_name, the_acl_type,
3001                                     the_acl);
3002                                 unbecome_root();
3003                                 if (sret == 0) {
3004                                         ret = True;     
3005                                 }
3006                         }
3007
3008                         if (ret == False) {
3009                                 DEBUG(2,("set_canon_ace_list: "
3010                                          "sys_acl_set_file type %s failed for "
3011                                          "file %s (%s).\n",
3012                                          the_acl_type == SMB_ACL_TYPE_DEFAULT ?
3013                                          "directory default" : "file",
3014                                          fsp_str_dbg(fsp), strerror(errno)));
3015                                 goto fail;
3016                         }
3017                 }
3018         } else {
3019                 if (SMB_VFS_SYS_ACL_SET_FD(fsp, the_acl) == -1) {
3020                         /*
3021                          * Some systems allow all the above calls and only fail with no ACL support
3022                          * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
3023                          */
3024                         if (no_acl_syscall_error(errno)) {
3025                                 *pacl_set_support = False;
3026                         }
3027
3028                         if (acl_group_override(conn, fsp->fsp_name)) {
3029                                 int sret;
3030
3031                                 DEBUG(5,("set_canon_ace_list: acl group "
3032                                          "control on and current user in file "
3033                                          "%s primary group.\n",
3034                                          fsp_str_dbg(fsp)));
3035
3036                                 become_root();
3037                                 sret = SMB_VFS_SYS_ACL_SET_FD(fsp, the_acl);
3038                                 unbecome_root();
3039                                 if (sret == 0) {
3040                                         ret = True;
3041                                 }
3042                         }
3043
3044                         if (ret == False) {
3045                                 DEBUG(2,("set_canon_ace_list: "
3046                                          "sys_acl_set_file failed for file %s "
3047                                          "(%s).\n",
3048                                          fsp_str_dbg(fsp), strerror(errno)));
3049                                 goto fail;
3050                         }
3051                 }
3052         }
3053
3054         ret = True;
3055
3056   fail:
3057
3058         if (the_acl != NULL) {
3059                 TALLOC_FREE(the_acl);
3060         }
3061
3062         return ret;
3063 }
3064
3065 /****************************************************************************
3066  
3067 ****************************************************************************/
3068
3069 SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
3070 {
3071         SMB_ACL_ENTRY_T entry;
3072
3073         if (!the_acl)
3074                 return NULL;
3075         if (sys_acl_get_entry(the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
3076                 TALLOC_FREE(the_acl);
3077                 return NULL;
3078         }
3079         return the_acl;
3080 }
3081
3082 /****************************************************************************
3083  Convert a canon_ace to a generic 3 element permission - if possible.
3084 ****************************************************************************/
3085
3086 #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
3087
3088 static bool convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
3089 {
3090         size_t ace_count = count_canon_ace_list(file_ace_list);
3091         canon_ace *ace_p;
3092         canon_ace *owner_ace = NULL;
3093         canon_ace *group_ace = NULL;
3094         canon_ace *other_ace = NULL;
3095
3096         if (ace_count != 3) {
3097                 DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE "
3098                          "entries for file %s to convert to posix perms.\n",
3099                          fsp_str_dbg(fsp)));
3100                 return False;
3101         }
3102
3103         for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
3104                 if (ace_p->owner_type == UID_ACE)
3105                         owner_ace = ace_p;
3106                 else if (ace_p->owner_type == GID_ACE)
3107                         group_ace = ace_p;
3108                 else if (ace_p->owner_type == WORLD_ACE)
3109                         other_ace = ace_p;
3110         }
3111
3112         if (!owner_ace || !group_ace || !other_ace) {
3113                 DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get "
3114                          "standard entries for file %s.\n", fsp_str_dbg(fsp)));
3115                 return False;
3116         }
3117
3118         *posix_perms = (mode_t)0;
3119
3120         *posix_perms |= owner_ace->perms;
3121         *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
3122         *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
3123         *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
3124         *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
3125         *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
3126         *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
3127
3128         /* The owner must have at least read access. */
3129
3130         *posix_perms |= S_IRUSR;
3131         if (fsp->is_directory)
3132                 *posix_perms |= (S_IWUSR|S_IXUSR);
3133
3134         DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o "
3135                   "to perm=0%o for file %s.\n", (int)owner_ace->perms,
3136                   (int)group_ace->perms, (int)other_ace->perms,
3137                   (int)*posix_perms, fsp_str_dbg(fsp)));
3138
3139         return True;
3140 }
3141
3142 /****************************************************************************
3143   Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and
3144   a normal POSIX acl. Win2k needs these split acls re-merging into one ACL
3145   with CI|OI set so it is inherited and also applies to the directory.
3146   Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
3147 ****************************************************************************/
3148
3149 static size_t merge_default_aces( struct security_ace *nt_ace_list, size_t num_aces)
3150 {
3151         size_t i, j;
3152
3153         for (i = 0; i < num_aces; i++) {
3154                 for (j = i+1; j < num_aces; j++) {
3155                         uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
3156                         uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
3157                         bool i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
3158                         bool j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
3159
3160                         /* We know the lower number ACE's are file entries. */
3161                         if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
3162                                 (nt_ace_list[i].size == nt_ace_list[j].size) &&
3163                                 (nt_ace_list[i].access_mask == nt_ace_list[j].access_mask) &&
3164                                 dom_sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
3165                                 (i_inh == j_inh) &&
3166                                 (i_flags_ni == 0) &&
3167                                 (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
3168                                                   SEC_ACE_FLAG_CONTAINER_INHERIT|
3169                                                   SEC_ACE_FLAG_INHERIT_ONLY))) {
3170                                 /*
3171                                  * W2K wants to have access allowed zero access ACE's
3172                                  * at the end of the list. If the mask is zero, merge
3173                                  * the non-inherited ACE onto the inherited ACE.
3174                                  */
3175
3176                                 if (nt_ace_list[i].access_mask == 0) {
3177                                         nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
3178                                                                 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
3179                                         if (num_aces - i - 1 > 0)
3180                                                 memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) *
3181                                                                 sizeof(struct security_ace));
3182
3183                                         DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
3184                                                 (unsigned int)i, (unsigned int)j ));
3185                                 } else {
3186                                         /*
3187                                          * These are identical except for the flags.
3188                                          * Merge the inherited ACE onto the non-inherited ACE.
3189                                          */
3190
3191                                         nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
3192                                                                 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
3193                                         if (num_aces - j - 1 > 0)
3194                                                 memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) *
3195                                                                 sizeof(struct security_ace));
3196
3197                                         DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
3198                                                 (unsigned int)j, (unsigned int)i ));
3199                                 }
3200                                 num_aces--;
3201                                 break;
3202                         }
3203                 }
3204         }
3205
3206         return num_aces;
3207 }
3208
3209 /*
3210  * Add or Replace ACE entry.
3211  * In some cases we need to add a specific ACE for compatibility reasons.
3212  * When doing that we must make sure we are not actually creating a duplicate
3213  * entry. So we need to search whether an ACE entry already exist and eventually
3214  * replacce the access mask, or add a completely new entry if none was found.
3215  *
3216  * This function assumes the array has enough space to add a new entry without
3217  * any reallocation of memory.
3218  */
3219
3220 static void add_or_replace_ace(struct security_ace *nt_ace_list, size_t *num_aces,
3221                                 const struct dom_sid *sid, enum security_ace_type type,
3222                                 uint32_t mask, uint8_t flags)
3223 {
3224         int i;
3225
3226         /* first search for a duplicate */
3227         for (i = 0; i < *num_aces; i++) {
3228                 if (dom_sid_equal(&nt_ace_list[i].trustee, sid) &&
3229                     (nt_ace_list[i].flags == flags)) break;
3230         }
3231
3232         if (i < *num_aces) { /* found */
3233                 nt_ace_list[i].type = type;
3234                 nt_ace_list[i].access_mask = mask;
3235                 DEBUG(10, ("Replacing ACE %d with SID %s and flags %02x\n",
3236                            i, sid_string_dbg(sid), flags));
3237                 return;
3238         }
3239
3240         /* not found, append it */
3241         init_sec_ace(&nt_ace_list[(*num_aces)++], sid, type, mask, flags);
3242 }
3243
3244
3245 /****************************************************************************
3246  Reply to query a security descriptor from an fsp. If it succeeds it allocates
3247  the space for the return elements and returns the size needed to return the
3248  security descriptor. This should be the only external function needed for
3249  the UNIX style get ACL.
3250 ****************************************************************************/
3251
3252 static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
3253                                       const char *name,
3254                                       const SMB_STRUCT_STAT *sbuf,
3255                                       struct pai_val *pal,
3256                                       SMB_ACL_T posix_acl,
3257                                       SMB_ACL_T def_acl,
3258                                       uint32_t security_info,
3259                                       TALLOC_CTX *mem_ctx,
3260                                       struct security_descriptor **ppdesc)
3261 {
3262         struct dom_sid owner_sid;
3263         struct dom_sid group_sid;
3264         size_t sd_size = 0;
3265         struct security_acl *psa = NULL;
3266         size_t num_acls = 0;
3267         size_t num_def_acls = 0;
3268         size_t num_aces = 0;
3269         canon_ace *file_ace = NULL;
3270         canon_ace *dir_ace = NULL;
3271         struct security_ace *nt_ace_list = NULL;
3272         size_t num_profile_acls = 0;
3273         struct dom_sid orig_owner_sid;
3274         struct security_descriptor *psd = NULL;
3275         int i;
3276
3277         /*
3278          * Get the owner, group and world SIDs.
3279          */
3280
3281         create_file_sids(sbuf, &owner_sid, &group_sid);
3282
3283         if (lp_profile_acls(SNUM(conn))) {
3284                 /* For WXP SP1 the owner must be administrators. */
3285                 sid_copy(&orig_owner_sid, &owner_sid);
3286                 sid_copy(&owner_sid, &global_sid_Builtin_Administrators);
3287                 sid_copy(&group_sid, &global_sid_Builtin_Users);
3288                 num_profile_acls = 3;
3289         }
3290
3291         if ((security_info & SECINFO_DACL) && !(security_info & SECINFO_PROTECTED_DACL)) {
3292
3293                 /*
3294                  * In the optimum case Creator Owner and Creator Group would be used for
3295                  * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
3296                  * would lead to usability problems under Windows: The Creator entries
3297                  * are only available in browse lists of directories and not for files;
3298                  * additionally the identity of the owning group couldn't be determined.
3299                  * We therefore use those identities only for Default ACLs. 
3300                  */
3301
3302                 /* Create the canon_ace lists. */
3303                 file_ace = canonicalise_acl(conn, name, posix_acl, sbuf,
3304                                             &owner_sid, &group_sid, pal,
3305                                             SMB_ACL_TYPE_ACCESS);
3306
3307                 /* We must have *some* ACLS. */
3308         
3309                 if (count_canon_ace_list(file_ace) == 0) {
3310                         DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", name));
3311                         goto done;
3312                 }
3313
3314                 if (S_ISDIR(sbuf->st_ex_mode) && def_acl) {
3315                         dir_ace = canonicalise_acl(conn, name, def_acl,
3316                                                    sbuf,
3317                                                    &global_sid_Creator_Owner,
3318                                                    &global_sid_Creator_Group,
3319                                                    pal, SMB_ACL_TYPE_DEFAULT);
3320                 }
3321
3322                 /*
3323                  * Create the NT ACE list from the canonical ace lists.
3324                  */
3325
3326                 {
3327                         canon_ace *ace;
3328                         enum security_ace_type nt_acl_type;
3329
3330                         num_acls = count_canon_ace_list(file_ace);
3331                         num_def_acls = count_canon_ace_list(dir_ace);
3332
3333                         /* Allocate the ace list. */
3334                         if ((nt_ace_list = talloc_array(talloc_tos(), struct security_ace,num_acls + num_profile_acls + num_def_acls)) == NULL) {
3335                                 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
3336                                 goto done;
3337                         }
3338
3339                         memset(nt_ace_list, '\0', (num_acls + num_def_acls) * sizeof(struct security_ace) );
3340
3341                         /*
3342                          * Create the NT ACE list from the canonical ace lists.
3343                          */
3344
3345                         for (ace = file_ace; ace != NULL; ace = ace->next) {
3346                                 uint32_t acc = map_canon_ace_perms(SNUM(conn),
3347                                                 &nt_acl_type,
3348                                                 ace->perms,
3349                                                 S_ISDIR(sbuf->st_ex_mode));
3350                                 init_sec_ace(&nt_ace_list[num_aces++],
3351                                         &ace->trustee,
3352                                         nt_acl_type,
3353                                         acc,
3354                                         ace->ace_flags);
3355                         }
3356
3357                         /* The User must have access to a profile share - even
3358                          * if we can't map the SID. */
3359                         if (lp_profile_acls(SNUM(conn))) {
3360                                 add_or_replace_ace(nt_ace_list, &num_aces,
3361                                                    &global_sid_Builtin_Users,
3362                                                    SEC_ACE_TYPE_ACCESS_ALLOWED,
3363                                                    FILE_GENERIC_ALL, 0);
3364                         }
3365
3366                         for (ace = dir_ace; ace != NULL; ace = ace->next) {
3367                                 uint32_t acc = map_canon_ace_perms(SNUM(conn),
3368                                                 &nt_acl_type,
3369                                                 ace->perms,
3370                                                 S_ISDIR(sbuf->st_ex_mode));
3371                                 init_sec_ace(&nt_ace_list[num_aces++],
3372                                         &ace->trustee,
3373                                         nt_acl_type,
3374                                         acc,
3375                                         ace->ace_flags |
3376                                         SEC_ACE_FLAG_OBJECT_INHERIT|
3377                                         SEC_ACE_FLAG_CONTAINER_INHERIT|
3378                                         SEC_ACE_FLAG_INHERIT_ONLY);
3379                         }
3380
3381                         /* The User must have access to a profile share - even
3382                          * if we can't map the SID. */
3383                         if (lp_profile_acls(SNUM(conn))) {
3384                                 add_or_replace_ace(nt_ace_list, &num_aces,
3385                                                 &global_sid_Builtin_Users,
3386                                                 SEC_ACE_TYPE_ACCESS_ALLOWED,
3387                                                 FILE_GENERIC_ALL,
3388                                                 SEC_ACE_FLAG_OBJECT_INHERIT |
3389                                                 SEC_ACE_FLAG_CONTAINER_INHERIT |
3390                                                 SEC_ACE_FLAG_INHERIT_ONLY);
3391                         }
3392
3393                         /*
3394                          * Merge POSIX default ACLs and normal ACLs into one NT ACE.
3395                          * Win2K needs this to get the inheritance correct when replacing ACLs
3396                          * on a directory tree. Based on work by Jim @ IBM.
3397                          */
3398
3399                         num_aces = merge_default_aces(nt_ace_list, num_aces);
3400
3401                         if (lp_profile_acls(SNUM(conn))) {
3402                                 for (i = 0; i < num_aces; i++) {
3403                                         if (dom_sid_equal(&nt_ace_list[i].trustee, &owner_sid)) {
3404                                                 add_or_replace_ace(nt_ace_list, &num_aces,
3405                                                                    &orig_owner_sid,
3406                                                                    nt_ace_list[i].type,
3407                                                                    nt_ace_list[i].access_mask,
3408                                                                    nt_ace_list[i].flags);
3409                                                 break;
3410                                         }
3411                                 }
3412                         }
3413                 }
3414
3415                 if (num_aces) {
3416                         if((psa = make_sec_acl( talloc_tos(), NT4_ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
3417                                 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
3418                                 goto done;
3419                         }
3420                 }
3421         } /* security_info & SECINFO_DACL */
3422
3423         psd = make_standard_sec_desc(mem_ctx,
3424                         (security_info & SECINFO_OWNER) ? &owner_sid : NULL,
3425                         (security_info & SECINFO_GROUP) ? &group_sid : NULL,
3426                         psa,
3427                         &sd_size);
3428
3429         if(!psd) {
3430                 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
3431                 sd_size = 0;
3432                 goto done;
3433         }
3434
3435         /*
3436          * Windows 2000: The DACL_PROTECTED flag in the security
3437          * descriptor marks the ACL as non-inheriting, i.e., no
3438          * ACEs from higher level directories propagate to this
3439          * ACL. In the POSIX ACL model permissions are only
3440          * inherited at file create time, so ACLs never contain
3441          * any ACEs that are inherited dynamically. The DACL_PROTECTED
3442          * flag doesn't seem to bother Windows NT.
3443          * Always set this if map acl inherit is turned off.
3444          */
3445         if (pal == NULL || !lp_map_acl_inherit(SNUM(conn))) {
3446                 psd->type |= SEC_DESC_DACL_PROTECTED;
3447         } else {
3448                 psd->type |= pal->sd_type;
3449         }
3450
3451         if (psd->dacl) {
3452                 dacl_sort_into_canonical_order(psd->dacl->aces, (unsigned int)psd->dacl->num_aces);
3453         }
3454
3455         *ppdesc = psd;
3456
3457  done:
3458
3459         if (posix_acl) {
3460                 TALLOC_FREE(posix_acl);
3461         }
3462         if (def_acl) {
3463                 TALLOC_FREE(def_acl);
3464         }
3465         free_canon_ace_list(file_ace);
3466         free_canon_ace_list(dir_ace);
3467         free_inherited_info(pal);
3468         TALLOC_FREE(nt_ace_list);
3469
3470         return NT_STATUS_OK;
3471 }
3472
3473 NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info,
3474                            TALLOC_CTX *mem_ctx,
3475                            struct security_descriptor **ppdesc)
3476 {
3477         SMB_STRUCT_STAT sbuf;
3478         SMB_ACL_T posix_acl = NULL;
3479         struct pai_val *pal;
3480         TALLOC_CTX *frame = talloc_stackframe();
3481         NTSTATUS status;
3482
3483         *ppdesc = NULL;
3484
3485         DEBUG(10,("posix_fget_nt_acl: called for file %s\n",
3486                   fsp_str_dbg(fsp)));
3487
3488         /* can it happen that fsp_name == NULL ? */
3489         if (fsp->is_directory ||  fsp->fh->fd == -1) {
3490                 status = posix_get_nt_acl(fsp->conn, fsp->fsp_name->base_name,
3491                                           security_info, mem_ctx, ppdesc);
3492                 TALLOC_FREE(frame);
3493                 return status;
3494         }
3495
3496         /* Get the stat struct for the owner info. */
3497         if(SMB_VFS_FSTAT(fsp, &sbuf) != 0) {
3498                 TALLOC_FREE(frame);
3499                 return map_nt_error_from_unix(errno);
3500         }
3501
3502         /* Get the ACL from the fd. */
3503         posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, frame);
3504
3505         pal = fload_inherited_info(fsp);
3506
3507         status = posix_get_nt_acl_common(fsp->conn, fsp->fsp_name->base_name,
3508                                          &sbuf, pal, posix_acl, NULL,
3509                                          security_info, mem_ctx, ppdesc);
3510         TALLOC_FREE(frame);
3511         return status;
3512 }
3513
3514 NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name,
3515                           uint32_t security_info,
3516                           TALLOC_CTX *mem_ctx,
3517                           struct security_descriptor **ppdesc)
3518 {
3519         SMB_ACL_T posix_acl = NULL;
3520         SMB_ACL_T def_acl = NULL;
3521         struct pai_val *pal;
3522         struct smb_filename smb_fname;
3523         int ret;
3524         TALLOC_CTX *frame = talloc_stackframe();
3525         NTSTATUS status;
3526
3527         *ppdesc = NULL;
3528
3529         DEBUG(10,("posix_get_nt_acl: called for file %s\n", name ));
3530
3531         ZERO_STRUCT(smb_fname);
3532         smb_fname.base_name = discard_const_p(char, name);
3533
3534         /* Get the stat struct for the owner info. */
3535         if (lp_posix_pathnames()) {
3536                 ret = SMB_VFS_LSTAT(conn, &smb_fname);
3537         } else {
3538                 ret = SMB_VFS_STAT(conn, &smb_fname);
3539         }
3540
3541         if (ret == -1) {
3542                 TALLOC_FREE(frame);
3543                 return map_nt_error_from_unix(errno);
3544         }
3545
3546         /* Get the ACL from the path. */
3547         posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, name,
3548                                              SMB_ACL_TYPE_ACCESS, frame);
3549
3550         /* If it's a directory get the default POSIX ACL. */
3551         if(S_ISDIR(smb_fname.st.st_ex_mode)) {
3552                 def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, name,
3553                                                    SMB_ACL_TYPE_DEFAULT, frame);
3554                 def_acl = free_empty_sys_acl(conn, def_acl);
3555         }
3556
3557         pal = load_inherited_info(conn, name);
3558
3559         status = posix_get_nt_acl_common(conn, name, &smb_fname.st, pal,
3560                                          posix_acl, def_acl, security_info,
3561                                          mem_ctx,
3562                                          ppdesc);
3563         TALLOC_FREE(frame);
3564         return status;
3565 }
3566
3567 /****************************************************************************
3568  Try to chown a file. We will be able to chown it under the following conditions.
3569
3570   1) If we have root privileges, then it will just work.
3571   2) If we have SeRestorePrivilege we can change the user + group to any other user. 
3572   3) If we have SeTakeOwnershipPrivilege we can change the user to the current user.
3573   4) If we have write permission to the file and dos_filemodes is set
3574      then allow chown to the currently authenticated user.
3575 ****************************************************************************/
3576
3577 NTSTATUS try_chown(files_struct *fsp, uid_t uid, gid_t gid)
3578 {
3579         NTSTATUS status;
3580
3581         if(!CAN_WRITE(fsp->conn)) {
3582                 return NT_STATUS_MEDIA_WRITE_PROTECTED;
3583         }
3584
3585         /* Case (1). */
3586         status = vfs_chown_fsp(fsp, uid, gid);
3587         if (NT_STATUS_IS_OK(status)) {
3588                 return status;
3589         }
3590
3591         /* Case (2) / (3) */
3592         if (lp_enable_privileges()) {
3593                 bool has_take_ownership_priv = security_token_has_privilege(
3594                                                 get_current_nttok(fsp->conn),
3595                                                 SEC_PRIV_TAKE_OWNERSHIP);
3596                 bool has_restore_priv = security_token_has_privilege(
3597                                                 get_current_nttok(fsp->conn),
3598                                                 SEC_PRIV_RESTORE);
3599
3600                 if (has_restore_priv) {
3601                         ; /* Case (2) */
3602                 } else if (has_take_ownership_priv) {
3603                         /* Case (3) */
3604                         if (uid == get_current_uid(fsp->conn)) {
3605                                 gid = (gid_t)-1;
3606                         } else {
3607                                 has_take_ownership_priv = false;
3608                         }
3609                 }
3610
3611                 if (has_take_ownership_priv || has_restore_priv) {
3612                         become_root();
3613                         status = vfs_chown_fsp(fsp, uid, gid);
3614                         unbecome_root();
3615                         return status;
3616                 }
3617         }
3618
3619         /* Case (4). */
3620         if (!lp_dos_filemode(SNUM(fsp->conn))) {
3621                 return NT_STATUS_ACCESS_DENIED;
3622         }
3623
3624         /* only allow chown to the current user. This is more secure,
3625            and also copes with the case where the SID in a take ownership ACL is
3626            a local SID on the users workstation
3627         */
3628         if (uid != get_current_uid(fsp->conn)) {
3629                 return NT_STATUS_ACCESS_DENIED;
3630         }
3631
3632         become_root();
3633         /* Keep the current file gid the same. */
3634         status = vfs_chown_fsp(fsp, uid, (gid_t)-1);
3635         unbecome_root();
3636
3637         return status;
3638 }
3639
3640 /****************************************************************************
3641  Reply to set a security descriptor on an fsp. security_info_sent is the
3642  description of the following NT ACL.
3643  This should be the only external function needed for the UNIX style set ACL.
3644  We make a copy of psd_orig as internal functions modify the elements inside
3645  it, even though it's a const pointer.
3646 ****************************************************************************/
3647
3648 NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd_orig)
3649 {
3650         connection_struct *conn = fsp->conn;
3651         uid_t user = (uid_t)-1;
3652         gid_t grp = (gid_t)-1;
3653         struct dom_sid file_owner_sid;
3654         struct dom_sid file_grp_sid;
3655         canon_ace *file_ace_list = NULL;
3656         canon_ace *dir_ace_list = NULL;
3657         bool acl_perms = False;
3658         mode_t orig_mode = (mode_t)0;
3659         NTSTATUS status;
3660         bool set_acl_as_root = false;
3661         bool acl_set_support = false;
3662         bool ret = false;
3663         struct security_descriptor *psd = NULL;
3664
3665         DEBUG(10,("set_nt_acl: called for file %s\n",
3666                   fsp_str_dbg(fsp)));
3667
3668         if (!CAN_WRITE(conn)) {
3669                 DEBUG(10,("set acl rejected on read-only share\n"));
3670                 return NT_STATUS_MEDIA_WRITE_PROTECTED;
3671         }
3672
3673         if (!psd_orig) {
3674                 return NT_STATUS_INVALID_PARAMETER;
3675         }
3676
3677         psd = dup_sec_desc(talloc_tos(), psd_orig);
3678         if (!psd) {
3679                 return NT_STATUS_NO_MEMORY;
3680         }
3681
3682         /*
3683          * Get the current state of the file.
3684          */
3685
3686         status = vfs_stat_fsp(fsp);
3687         if (!NT_STATUS_IS_OK(status)) {
3688                 return status;
3689         }
3690
3691         /* Save the original element we check against. */
3692         orig_mode = fsp->fsp_name->st.st_ex_mode;
3693
3694         /*
3695          * Unpack the user/group/world id's.
3696          */
3697
3698         /* POSIX can't cope with missing owner/group. */
3699         if ((security_info_sent & SECINFO_OWNER) && (psd->owner_sid == NULL)) {
3700                 security_info_sent &= ~SECINFO_OWNER;
3701         }
3702         if ((security_info_sent & SECINFO_GROUP) && (psd->group_sid == NULL)) {
3703                 security_info_sent &= ~SECINFO_GROUP;
3704         }
3705
3706         status = unpack_nt_owners( conn, &user, &grp, security_info_sent, psd);
3707         if (!NT_STATUS_IS_OK(status)) {
3708                 return status;
3709         }
3710
3711         /*
3712          * Do we need to chown ? If so this must be done first as the incoming
3713          * CREATOR_OWNER acl will be relative to the *new* owner, not the old.
3714          * Noticed by Simo.
3715          */
3716
3717         if (((user != (uid_t)-1) && (fsp->fsp_name->st.st_ex_uid != user)) ||
3718             (( grp != (gid_t)-1) && (fsp->fsp_name->st.st_ex_gid != grp))) {
3719
3720                 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3721                          fsp_str_dbg(fsp), (unsigned int)user,
3722                          (unsigned int)grp));
3723
3724                 status = try_chown(fsp, user, grp);
3725                 if(!NT_STATUS_IS_OK(status)) {
3726                         DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error "
3727                                 "= %s.\n", fsp_str_dbg(fsp),
3728                                 (unsigned int)user,
3729                                 (unsigned int)grp,
3730                                 nt_errstr(status)));
3731                         return status;
3732                 }
3733
3734                 /*
3735                  * Recheck the current state of the file, which may have changed.
3736                  * (suid/sgid bits, for instance)
3737                  */
3738
3739                 status = vfs_stat_fsp(fsp);
3740                 if (!NT_STATUS_IS_OK(status)) {
3741                         return status;
3742                 }
3743
3744                 /* Save the original element we check against. */
3745                 orig_mode = fsp->fsp_name->st.st_ex_mode;
3746
3747                 /* If we successfully chowned, we know we must
3748                  * be able to set the acl, so do it as root.
3749                  */
3750                 set_acl_as_root = true;
3751         }
3752
3753         create_file_sids(&fsp->fsp_name->st, &file_owner_sid, &file_grp_sid);
3754
3755         if((security_info_sent & SECINFO_DACL) &&
3756                         (psd->type & SEC_DESC_DACL_PRESENT) &&
3757                         (psd->dacl == NULL)) {
3758                 struct security_ace ace[3];
3759
3760                 /* We can't have NULL DACL in POSIX.
3761                    Use owner/group/Everyone -> full access. */
3762
3763                 init_sec_ace(&ace[0],
3764                                 &file_owner_sid,
3765                                 SEC_ACE_TYPE_ACCESS_ALLOWED,
3766                                 GENERIC_ALL_ACCESS,
3767                                 0);
3768                 init_sec_ace(&ace[1],
3769                                 &file_grp_sid,
3770                                 SEC_ACE_TYPE_ACCESS_ALLOWED,
3771                                 GENERIC_ALL_ACCESS,
3772                                 0);
3773                 init_sec_ace(&ace[2],
3774                                 &global_sid_World,
3775                                 SEC_ACE_TYPE_ACCESS_ALLOWED,
3776                                 GENERIC_ALL_ACCESS,
3777                                 0);
3778                 psd->dacl = make_sec_acl(talloc_tos(),
3779                                         NT4_ACL_REVISION,
3780                                         3,
3781                                         ace);
3782                 if (psd->dacl == NULL) {
3783                         return NT_STATUS_NO_MEMORY;
3784                 }
3785                 security_acl_map_generic(psd->dacl, &file_generic_mapping);
3786         }
3787
3788         acl_perms = unpack_canon_ace(fsp, &fsp->fsp_name->st, &file_owner_sid,
3789                                      &file_grp_sid, &file_ace_list,
3790                                      &dir_ace_list, security_info_sent, psd);
3791
3792         /* Ignore W2K traverse DACL set. */
3793         if (!file_ace_list && !dir_ace_list) {
3794                 return NT_STATUS_OK;
3795         }
3796
3797         if (!acl_perms) {
3798                 DEBUG(3,("set_nt_acl: cannot set permissions\n"));
3799                 free_canon_ace_list(file_ace_list);
3800                 free_canon_ace_list(dir_ace_list);
3801                 return NT_STATUS_ACCESS_DENIED;
3802         }
3803
3804         /*
3805          * Only change security if we got a DACL.
3806          */
3807
3808         if(!(security_info_sent & SECINFO_DACL) || (psd->dacl == NULL)) {
3809                 free_canon_ace_list(file_ace_list);
3810                 free_canon_ace_list(dir_ace_list);
3811                 return NT_STATUS_OK;
3812         }
3813
3814         /*
3815          * Try using the POSIX ACL set first. Fall back to chmod if
3816          * we have no ACL support on this filesystem.
3817          */
3818
3819         if (acl_perms && file_ace_list) {
3820                 if (set_acl_as_root) {
3821                         become_root();
3822                 }
3823                 ret = set_canon_ace_list(fsp, file_ace_list, false,
3824                                          &fsp->fsp_name->st, &acl_set_support);
3825                 if (set_acl_as_root) {
3826                         unbecome_root();
3827                 }
3828                 if (acl_set_support && ret == false) {
3829                         DEBUG(3,("set_nt_acl: failed to set file acl on file "
3830                                  "%s (%s).\n", fsp_str_dbg(fsp),
3831                                  strerror(errno)));
3832                         free_canon_ace_list(file_ace_list);
3833                         free_canon_ace_list(dir_ace_list);
3834                         return map_nt_error_from_unix(errno);
3835                 }
3836         }
3837
3838         if (acl_perms && acl_set_support && fsp->is_directory) {
3839                 if (dir_ace_list) {
3840                         if (set_acl_as_root) {
3841                                 become_root();
3842                         }
3843                         ret = set_canon_ace_list(fsp, dir_ace_list, true,
3844                                                  &fsp->fsp_name->st,
3845                                                  &acl_set_support);
3846                         if (set_acl_as_root) {
3847                                 unbecome_root();
3848                         }
3849                         if (ret == false) {
3850                                 DEBUG(3,("set_nt_acl: failed to set default "
3851                                          "acl on directory %s (%s).\n",
3852                                          fsp_str_dbg(fsp), strerror(errno)));
3853                                 free_canon_ace_list(file_ace_list);
3854                                 free_canon_ace_list(dir_ace_list);
3855                                 return map_nt_error_from_unix(errno);
3856                         }
3857                 } else {
3858                         int sret = -1;
3859
3860                         /*
3861                          * No default ACL - delete one if it exists.
3862                          */
3863
3864                         if (set_acl_as_root) {
3865                                 become_root();
3866                         }
3867                         sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn,
3868                             fsp->fsp_name->base_name);
3869                         if (set_acl_as_root) {
3870                                 unbecome_root();
3871                         }
3872                         if (sret == -1) {
3873                                 if (acl_group_override(conn, fsp->fsp_name)) {
3874                                         DEBUG(5,("set_nt_acl: acl group "
3875                                                  "control on and current user "
3876                                                  "in file %s primary group. "
3877                                                  "Override delete_def_acl\n",
3878                                                  fsp_str_dbg(fsp)));
3879
3880                                         become_root();
3881                                         sret =
3882                                             SMB_VFS_SYS_ACL_DELETE_DEF_FILE(
3883                                                     conn,
3884                                                     fsp->fsp_name->base_name);
3885                                         unbecome_root();
3886                                 }
3887
3888                                 if (sret == -1) {
3889                                         DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
3890                                         free_canon_ace_list(file_ace_list);
3891                                         free_canon_ace_list(dir_ace_list);
3892                                         return map_nt_error_from_unix(errno);
3893                                 }
3894                         }
3895                 }
3896         }
3897
3898         if (acl_set_support) {
3899                 if (set_acl_as_root) {
3900                         become_root();
3901                 }
3902                 store_inheritance_attributes(fsp,
3903                                 file_ace_list,
3904                                 dir_ace_list,
3905                                 psd->type);
3906                 if (set_acl_as_root) {
3907                         unbecome_root();
3908                 }
3909         }
3910
3911         /*
3912          * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
3913          */
3914
3915         if(!acl_set_support && acl_perms) {
3916                 mode_t posix_perms;
3917
3918                 if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
3919                         free_canon_ace_list(file_ace_list);
3920                         free_canon_ace_list(dir_ace_list);
3921                         DEBUG(3,("set_nt_acl: failed to convert file acl to "
3922                                  "posix permissions for file %s.\n",
3923                                  fsp_str_dbg(fsp)));
3924                         return NT_STATUS_ACCESS_DENIED;
3925                 }
3926
3927                 if (orig_mode != posix_perms) {
3928                         int sret = -1;
3929
3930                         DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
3931                                  fsp_str_dbg(fsp), (unsigned int)posix_perms));
3932
3933                         if (set_acl_as_root) {
3934                                 become_root();
3935                         }
3936                         sret = SMB_VFS_CHMOD(conn, fsp->fsp_name->base_name,
3937                                              posix_perms);
3938                         if (set_acl_as_root) {
3939                                 unbecome_root();
3940                         }
3941                         if(sret == -1) {
3942                                 if (acl_group_override(conn, fsp->fsp_name)) {
3943                                         DEBUG(5,("set_nt_acl: acl group "
3944                                                  "control on and current user "
3945                                                  "in file %s primary group. "
3946                                                  "Override chmod\n",
3947                                                  fsp_str_dbg(fsp)));
3948
3949                                         become_root();
3950                                         sret = SMB_VFS_CHMOD(conn,
3951                                             fsp->fsp_name->base_name,
3952                                             posix_perms);
3953                                         unbecome_root();
3954                                 }
3955
3956                                 if (sret == -1) {
3957                                         DEBUG(3,("set_nt_acl: chmod %s, 0%o "
3958                                                  "failed. Error = %s.\n",
3959                                                  fsp_str_dbg(fsp),
3960                                                  (unsigned int)posix_perms,
3961                                                  strerror(errno)));
3962                                         free_canon_ace_list(file_ace_list);
3963                                         free_canon_ace_list(dir_ace_list);
3964                                         return map_nt_error_from_unix(errno);
3965                                 }
3966                         }
3967                 }
3968         }
3969
3970         free_canon_ace_list(file_ace_list);
3971         free_canon_ace_list(dir_ace_list);
3972
3973         /* Ensure the stat struct in the fsp is correct. */
3974         status = vfs_stat_fsp(fsp);
3975
3976         return NT_STATUS_OK;
3977 }
3978
3979 /****************************************************************************
3980  Get the actual group bits stored on a file with an ACL. Has no effect if
3981  the file has no ACL. Needed in dosmode code where the stat() will return
3982  the mask bits, not the real group bits, for a file with an ACL.
3983 ****************************************************************************/
3984
3985 int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode )
3986 {
3987         int entry_id = SMB_ACL_FIRST_ENTRY;
3988         SMB_ACL_ENTRY_T entry;
3989         SMB_ACL_T posix_acl;
3990         int result = -1;
3991
3992         posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname,
3993                                              SMB_ACL_TYPE_ACCESS, talloc_tos());
3994         if (posix_acl == (SMB_ACL_T)NULL)
3995                 return -1;
3996
3997         while (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
3998                 SMB_ACL_TAG_T tagtype;
3999                 SMB_ACL_PERMSET_T permset;
4000
4001                 entry_id = SMB_ACL_NEXT_ENTRY;
4002
4003                 if (sys_acl_get_tag_type(entry, &tagtype) ==-1)
4004                         break;
4005
4006                 if (tagtype == SMB_ACL_GROUP_OBJ) {
4007                         if (sys_acl_get_permset(entry, &permset) == -1) {
4008                                 break;
4009                         } else {
4010                                 *mode &= ~(S_IRGRP|S_IWGRP|S_IXGRP);
4011                                 *mode |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? S_IRGRP : 0);
4012                                 *mode |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? S_IWGRP : 0);
4013                                 *mode |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0);
4014                                 result = 0;
4015                                 break;
4016                         }
4017                 }
4018         }
4019         TALLOC_FREE(posix_acl);
4020         return result;
4021 }
4022
4023 /****************************************************************************
4024  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
4025  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
4026 ****************************************************************************/
4027
4028 static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode)
4029 {
4030         int entry_id = SMB_ACL_FIRST_ENTRY;
4031         SMB_ACL_ENTRY_T entry;
4032         int num_entries = 0;
4033
4034         while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
4035                 SMB_ACL_TAG_T tagtype;
4036                 SMB_ACL_PERMSET_T permset;
4037                 mode_t perms;
4038
4039                 entry_id = SMB_ACL_NEXT_ENTRY;
4040
4041                 if (sys_acl_get_tag_type(entry, &tagtype) == -1)
4042                         return -1;
4043
4044                 if (sys_acl_get_permset(entry, &permset) == -1)
4045                         return -1;
4046
4047                 num_entries++;
4048
4049                 switch(tagtype) {
4050                         case SMB_ACL_USER_OBJ:
4051                                 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
4052                                 break;
4053                         case SMB_ACL_GROUP_OBJ:
4054                                 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
4055                                 break;
4056                         case SMB_ACL_MASK:
4057                                 /*
4058                                  * FIXME: The ACL_MASK entry permissions should really be set to
4059                                  * the union of the permissions of all ACL_USER,
4060                                  * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
4061                                  * acl_calc_mask() does, but Samba ACLs doesn't provide it.
4062                                  */
4063                                 perms = S_IRUSR|S_IWUSR|S_IXUSR;
4064                                 break;
4065                         case SMB_ACL_OTHER:
4066                                 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
4067                                 break;
4068                         default:
4069                                 continue;
4070                 }
4071
4072                 if (map_acl_perms_to_permset(conn, perms, &permset) == -1)
4073                         return -1;
4074
4075                 if (sys_acl_set_permset(entry, permset) == -1)
4076                         return -1;
4077         }
4078
4079         /*
4080          * If this is a simple 3 element ACL or no elements then it's a standard
4081          * UNIX permission set. Just use chmod...       
4082          */
4083
4084         if ((num_entries == 3) || (num_entries == 0))
4085                 return -1;
4086
4087         return 0;
4088 }
4089
4090 /****************************************************************************
4091  Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
4092  GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
4093  resulting ACL on TO.  Note that name is in UNIX character set.
4094 ****************************************************************************/
4095
4096 static int copy_access_posix_acl(connection_struct *conn, const char *from, const char *to, mode_t mode)
4097 {
4098         SMB_ACL_T posix_acl = NULL;
4099         int ret = -1;
4100
4101         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from,
4102                                                   SMB_ACL_TYPE_ACCESS,
4103                                                   talloc_tos())) == NULL)
4104                 return -1;
4105
4106         if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
4107                 goto done;
4108
4109         ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl);
4110
4111  done:
4112
4113         TALLOC_FREE(posix_acl);
4114         return ret;
4115 }
4116
4117 /****************************************************************************
4118  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
4119  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
4120  Note that name is in UNIX character set.
4121 ****************************************************************************/
4122
4123 int chmod_acl(connection_struct *conn, const char *name, mode_t mode)
4124 {
4125         return copy_access_posix_acl(conn, name, name, mode);
4126 }
4127
4128 /****************************************************************************
4129  Check for an existing default POSIX ACL on a directory.
4130 ****************************************************************************/
4131
4132 static bool directory_has_default_posix_acl(connection_struct *conn, const char *fname)
4133 {
4134         SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname,
4135                                                      SMB_ACL_TYPE_DEFAULT,
4136                                                      talloc_tos());
4137         bool has_acl = False;
4138         SMB_ACL_ENTRY_T entry;
4139
4140         if (def_acl != NULL && (sys_acl_get_entry(def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) {
4141                 has_acl = True;
4142         }
4143
4144         if (def_acl) {
4145                 TALLOC_FREE(def_acl);
4146         }
4147         return has_acl;
4148 }
4149
4150 /****************************************************************************
4151  If the parent directory has no default ACL but it does have an Access ACL,
4152  inherit this Access ACL to file name.
4153 ****************************************************************************/
4154
4155 int inherit_access_posix_acl(connection_struct *conn, const char *inherit_from_dir,
4156                        const char *name, mode_t mode)
4157 {
4158         if (directory_has_default_posix_acl(conn, inherit_from_dir))
4159                 return 0;
4160
4161         return copy_access_posix_acl(conn, inherit_from_dir, name, mode);
4162 }
4163
4164 /****************************************************************************
4165  Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
4166  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
4167 ****************************************************************************/
4168
4169 int fchmod_acl(files_struct *fsp, mode_t mode)
4170 {
4171         connection_struct *conn = fsp->conn;
4172         SMB_ACL_T posix_acl = NULL;
4173         int ret = -1;
4174
4175         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, talloc_tos())) == NULL)
4176                 return -1;
4177
4178         if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
4179                 goto done;
4180
4181         ret = SMB_VFS_SYS_ACL_SET_FD(fsp, posix_acl);
4182
4183   done:
4184
4185         TALLOC_FREE(posix_acl);
4186         return ret;
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 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 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 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 bool set_unix_posix_default_acl(connection_struct *conn, const char *fname, const SMB_STRUCT_STAT *psbuf,
4352                                 uint16 num_def_acls, const char *pdata)
4353 {
4354         SMB_ACL_T def_acl = NULL;
4355
4356         if (!S_ISDIR(psbuf->st_ex_mode)) {
4357                 if (num_def_acls) {
4358                         DEBUG(5,("set_unix_posix_default_acl: Can't set default ACL on non-directory file %s\n", fname ));
4359                         errno = EISDIR;
4360                         return False;
4361                 } else {
4362                         return True;
4363                 }
4364         }
4365
4366         if (!num_def_acls) {
4367                 /* Remove the default ACL. */
4368                 if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fname) == -1) {
4369                         DEBUG(5,("set_unix_posix_default_acl: acl_delete_def_file failed on directory %s (%s)\n",
4370                                 fname, strerror(errno) ));
4371                         return False;
4372                 }
4373                 return True;
4374         }
4375
4376         if ((def_acl = create_posix_acl_from_wire(conn, num_def_acls,
4377                                                   pdata,
4378                                                   talloc_tos())) == NULL) {
4379                 return False;
4380         }
4381
4382         if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT, def_acl) == -1) {
4383                 DEBUG(5,("set_unix_posix_default_acl: acl_set_file failed on directory %s (%s)\n",
4384                         fname, strerror(errno) ));
4385                 TALLOC_FREE(def_acl);
4386                 return False;
4387         }
4388
4389         DEBUG(10,("set_unix_posix_default_acl: set default acl for file %s\n", fname ));
4390         TALLOC_FREE(def_acl);
4391         return True;
4392 }
4393
4394 /****************************************************************************
4395  Remove an ACL from a file. As we don't have acl_delete_entry() available
4396  we must read the current acl and copy all entries except MASK, USER and GROUP
4397  to a new acl, then set that. This (at least on Linux) causes any ACL to be
4398  removed.
4399  FIXME ! How does the share mask/mode fit into this.... ?
4400 ****************************************************************************/
4401
4402 static bool remove_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname)
4403 {
4404         SMB_ACL_T file_acl = NULL;
4405         int entry_id = SMB_ACL_FIRST_ENTRY;
4406         SMB_ACL_ENTRY_T entry;
4407         bool ret = False;
4408         /* Create a new ACL with only 3 entries, u/g/w. */
4409         SMB_ACL_T new_file_acl = sys_acl_init(talloc_tos());
4410         SMB_ACL_ENTRY_T user_ent = NULL;
4411         SMB_ACL_ENTRY_T group_ent = NULL;
4412         SMB_ACL_ENTRY_T other_ent = NULL;
4413
4414         if (new_file_acl == NULL) {
4415                 DEBUG(5,("remove_posix_acl: failed to init new ACL with 3 entries for file %s.\n", fname));
4416                 return False;
4417         }
4418
4419         /* Now create the u/g/w entries. */
4420         if (sys_acl_create_entry(&new_file_acl, &user_ent) == -1) {
4421                 DEBUG(5,("remove_posix_acl: Failed to create user entry for file %s. (%s)\n",
4422                         fname, strerror(errno) ));
4423                 goto done;
4424         }
4425         if (sys_acl_set_tag_type(user_ent, SMB_ACL_USER_OBJ) == -1) {
4426                 DEBUG(5,("remove_posix_acl: Failed to set user entry for file %s. (%s)\n",
4427                         fname, strerror(errno) ));
4428                 goto done;
4429         }
4430
4431         if (sys_acl_create_entry(&new_file_acl, &group_ent) == -1) {
4432                 DEBUG(5,("remove_posix_acl: Failed to create group entry for file %s. (%s)\n",
4433                         fname, strerror(errno) ));
4434                 goto done;
4435         }
4436         if (sys_acl_set_tag_type(group_ent, SMB_ACL_GROUP_OBJ) == -1) {
4437                 DEBUG(5,("remove_posix_acl: Failed to set group entry for file %s. (%s)\n",
4438                         fname, strerror(errno) ));
4439                 goto done;
4440         }
4441
4442         if (sys_acl_create_entry(&new_file_acl, &other_ent) == -1) {
4443                 DEBUG(5,("remove_posix_acl: Failed to create other entry for file %s. (%s)\n",
4444                         fname, strerror(errno) ));
4445                 goto done;
4446         }
4447         if (sys_acl_set_tag_type(other_ent, SMB_ACL_OTHER) == -1) {
4448                 DEBUG(5,("remove_posix_acl: Failed to set other entry for file %s. (%s)\n",
4449                         fname, strerror(errno) ));
4450                 goto done;
4451         }
4452
4453         /* Get the current file ACL. */
4454         if (fsp && fsp->fh->fd != -1) {
4455                 file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, talloc_tos());
4456         } else {
4457                 file_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname,
4458                                                     SMB_ACL_TYPE_ACCESS,
4459                                                     talloc_tos());
4460         }
4461
4462         if (file_acl == NULL) {
4463                 /* This is only returned if an error occurred. Even for a file with
4464                    no acl a u/g/w acl should be returned. */
4465                 DEBUG(5,("remove_posix_acl: failed to get ACL from file %s (%s).\n",
4466                         fname, strerror(errno) ));
4467                 goto done;
4468         }
4469
4470         while ( sys_acl_get_entry(file_acl, entry_id, &entry) == 1) {
4471                 SMB_ACL_TAG_T tagtype;
4472                 SMB_ACL_PERMSET_T permset;
4473
4474                 entry_id = SMB_ACL_NEXT_ENTRY;
4475
4476                 if (sys_acl_get_tag_type(entry, &tagtype) == -1) {
4477                         DEBUG(5,("remove_posix_acl: failed to get tagtype from ACL on file %s (%s).\n",
4478                                 fname, strerror(errno) ));
4479                         goto done;
4480                 }
4481
4482                 if (sys_acl_get_permset(entry, &permset) == -1) {
4483                         DEBUG(5,("remove_posix_acl: failed to get permset from ACL on file %s (%s).\n",
4484                                 fname, strerror(errno) ));
4485                         goto done;
4486                 }
4487
4488                 if (tagtype == SMB_ACL_USER_OBJ) {
4489                         if (sys_acl_set_permset(user_ent, permset) == -1) {
4490                                 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
4491                                         fname, strerror(errno) ));
4492                         }
4493                 } else if (tagtype == SMB_ACL_GROUP_OBJ) {
4494                         if (sys_acl_set_permset(group_ent, permset) == -1) {
4495                                 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
4496                                         fname, strerror(errno) ));
4497                         }
4498                 } else if (tagtype == SMB_ACL_OTHER) {
4499                         if (sys_acl_set_permset(other_ent, permset) == -1) {
4500                                 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
4501                                         fname, strerror(errno) ));
4502                         }
4503                 }
4504         }
4505
4506         /* Set the new empty file ACL. */
4507         if (fsp && fsp->fh->fd != -1) {
4508                 if (SMB_VFS_SYS_ACL_SET_FD(fsp, new_file_acl) == -1) {
4509                         DEBUG(5,("remove_posix_acl: acl_set_file failed on %s (%s)\n",
4510                                 fname, strerror(errno) ));
4511                         goto done;
4512                 }
4513         } else {
4514                 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, new_file_acl) == -1) {
4515                         DEBUG(5,("remove_posix_acl: acl_set_file failed on %s (%s)\n",
4516                                 fname, strerror(errno) ));
4517                         goto done;
4518                 }
4519         }
4520
4521         ret = True;
4522
4523  done:
4524
4525         if (file_acl) {
4526                 TALLOC_FREE(file_acl);
4527         }
4528         if (new_file_acl) {
4529                 TALLOC_FREE(new_file_acl);
4530         }
4531         return ret;
4532 }
4533
4534 /****************************************************************************
4535  Calls from UNIX extensions - POSIX ACL set.
4536  If num_def_acls == 0 then read/modify/write acl after removing all entries
4537  except SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER.
4538 ****************************************************************************/
4539
4540 bool set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname, uint16 num_acls, const char *pdata)
4541 {
4542         SMB_ACL_T file_acl = NULL;
4543
4544         if (!num_acls) {
4545                 /* Remove the ACL from the file. */
4546                 return remove_posix_acl(conn, fsp, fname);
4547         }
4548
4549         if ((file_acl = create_posix_acl_from_wire(conn, num_acls,
4550                                                    pdata,
4551                                                    talloc_tos())) == NULL) {
4552                 return False;
4553         }
4554
4555         if (fsp && fsp->fh->fd != -1) {
4556                 /* The preferred way - use an open fd. */
4557                 if (SMB_VFS_SYS_ACL_SET_FD(fsp, file_acl) == -1) {
4558                         DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
4559                                 fname, strerror(errno) ));
4560                         TALLOC_FREE(file_acl);
4561                         return False;
4562                 }
4563         } else {
4564                 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, file_acl) == -1) {
4565                         DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
4566                                 fname, strerror(errno) ));
4567                         TALLOC_FREE(file_acl);
4568                         return False;
4569                 }
4570         }
4571
4572         DEBUG(10,("set_unix_posix_acl: set acl for file %s\n", fname ));
4573         TALLOC_FREE(file_acl);
4574         return True;
4575 }
4576
4577 /********************************************************************
4578  Pull the NT ACL from a file on disk or the OpenEventlog() access
4579  check.  Caller is responsible for freeing the returned security
4580  descriptor via TALLOC_FREE().  This is designed for dealing with 
4581  user space access checks in smbd outside of the VFS.  For example,
4582  checking access rights in OpenEventlog() or from python.
4583
4584 ********************************************************************/
4585
4586 NTSTATUS get_nt_acl_no_snum(TALLOC_CTX *ctx, const char *fname,
4587                                 uint32 security_info_wanted,
4588                                 struct security_descriptor **sd)
4589 {
4590         TALLOC_CTX *frame = talloc_stackframe();
4591         connection_struct *conn;
4592         NTSTATUS status = NT_STATUS_OK;
4593
4594         if (!posix_locking_init(false)) {
4595                 TALLOC_FREE(frame);
4596                 return NT_STATUS_NO_MEMORY;
4597         }
4598
4599         status = create_conn_struct(ctx,
4600                                 server_event_context(),
4601                                 server_messaging_context(),
4602                                 &conn,
4603                                 -1,
4604                                 "/",
4605                                 NULL);
4606
4607         if (!NT_STATUS_IS_OK(status)) {
4608                 DEBUG(0,("create_conn_struct returned %s.\n",
4609                         nt_errstr(status)));
4610                 TALLOC_FREE(frame);
4611                 return status;
4612         }
4613
4614         status = SMB_VFS_GET_NT_ACL(conn, fname, security_info_wanted, ctx, sd);
4615         if (!NT_STATUS_IS_OK(status)) {
4616                 DEBUG(0, ("get_nt_acl_no_snum: SMB_VFS_GET_NT_ACL returned %s.\n",
4617                           nt_errstr(status)));
4618         }
4619
4620         conn_free(conn);
4621         TALLOC_FREE(frame);
4622
4623         return status;
4624 }
4625
4626 /* Stolen shamelessly from pvfs_default_acl() in source4 :-). */
4627
4628 NTSTATUS make_default_filesystem_acl(TALLOC_CTX *ctx,
4629                                         const char *name,
4630                                         SMB_STRUCT_STAT *psbuf,
4631                                         struct security_descriptor **ppdesc)
4632 {
4633         struct dom_sid owner_sid, group_sid;
4634         size_t size = 0;
4635         struct security_ace aces[4];
4636         uint32_t access_mask = 0;
4637         mode_t mode = psbuf->st_ex_mode;
4638         struct security_acl *new_dacl = NULL;
4639         int idx = 0;
4640
4641         DEBUG(10,("make_default_filesystem_acl: file %s mode = 0%o\n",
4642                 name, (int)mode ));
4643
4644         uid_to_sid(&owner_sid, psbuf->st_ex_uid);
4645         gid_to_sid(&group_sid, psbuf->st_ex_gid);
4646
4647         /*
4648          We provide up to 4 ACEs
4649                 - Owner
4650                 - Group
4651                 - Everyone
4652                 - NT System
4653         */
4654
4655         if (mode & S_IRUSR) {
4656                 if (mode & S_IWUSR) {
4657                         access_mask |= SEC_RIGHTS_FILE_ALL;
4658                 } else {
4659                         access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
4660                 }
4661         }
4662         if (mode & S_IWUSR) {
4663                 access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
4664         }
4665
4666         init_sec_ace(&aces[idx],
4667                         &owner_sid,
4668                         SEC_ACE_TYPE_ACCESS_ALLOWED,
4669                         access_mask,
4670                         0);
4671         idx++;
4672
4673         access_mask = 0;
4674         if (mode & S_IRGRP) {
4675                 access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
4676         }
4677         if (mode & S_IWGRP) {
4678                 /* note that delete is not granted - this matches posix behaviour */
4679                 access_mask |= SEC_RIGHTS_FILE_WRITE;
4680         }
4681         if (access_mask) {
4682                 init_sec_ace(&aces[idx],
4683                         &group_sid,
4684                         SEC_ACE_TYPE_ACCESS_ALLOWED,
4685                         access_mask,
4686                         0);
4687                 idx++;
4688         }
4689
4690         access_mask = 0;
4691         if (mode & S_IROTH) {
4692                 access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
4693         }
4694         if (mode & S_IWOTH) {
4695                 access_mask |= SEC_RIGHTS_FILE_WRITE;
4696         }
4697         if (access_mask) {
4698                 init_sec_ace(&aces[idx],
4699                         &global_sid_World,
4700                         SEC_ACE_TYPE_ACCESS_ALLOWED,
4701                         access_mask,
4702                         0);
4703                 idx++;
4704         }
4705
4706         init_sec_ace(&aces[idx],
4707                         &global_sid_System,
4708                         SEC_ACE_TYPE_ACCESS_ALLOWED,
4709                         SEC_RIGHTS_FILE_ALL,
4710                         0);
4711         idx++;
4712
4713         new_dacl = make_sec_acl(ctx,
4714                         NT4_ACL_REVISION,
4715                         idx,
4716                         aces);
4717
4718         if (!new_dacl) {
4719                 return NT_STATUS_NO_MEMORY;
4720         }
4721
4722         *ppdesc = make_sec_desc(ctx,
4723                         SECURITY_DESCRIPTOR_REVISION_1,
4724                         SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
4725                         &owner_sid,
4726                         &group_sid,
4727                         NULL,
4728                         new_dacl,
4729                         &size);
4730         if (!*ppdesc) {
4731                 return NT_STATUS_NO_MEMORY;
4732         }
4733         return NT_STATUS_OK;
4734 }
4735
4736 int posix_sys_acl_blob_get_file(vfs_handle_struct *handle,
4737                                 const char *path_p,
4738                                 TALLOC_CTX *mem_ctx,
4739                                 char **blob_description,
4740                                 DATA_BLOB *blob)
4741 {
4742         int ret;
4743         TALLOC_CTX *frame = talloc_stackframe();
4744         /* Initialise this to zero, in a portable way */
4745         struct smb_acl_wrapper acl_wrapper = {
4746                 NULL
4747         };
4748         struct smb_filename *smb_fname;
4749
4750         smb_fname = synthetic_smb_fname_split(frame, path_p, NULL);
4751         if (smb_fname == NULL) {
4752                 TALLOC_FREE(frame);
4753                 errno = ENOMEM;
4754                 return -1;
4755         }
4756
4757         acl_wrapper.access_acl
4758                 = smb_vfs_call_sys_acl_get_file(handle,
4759                                                 path_p,
4760                                                 SMB_ACL_TYPE_ACCESS,
4761                                                 frame);
4762
4763         ret = smb_vfs_call_stat(handle, smb_fname);
4764         if (ret == -1) {
4765                 TALLOC_FREE(frame);
4766                 return -1;
4767         }
4768
4769         if (S_ISDIR(smb_fname->st.st_ex_mode)) {
4770                 acl_wrapper.default_acl
4771                         = smb_vfs_call_sys_acl_get_file(handle,
4772                                                         path_p,
4773                                                         SMB_ACL_TYPE_DEFAULT,
4774                                                         frame);
4775         }
4776
4777         acl_wrapper.owner = smb_fname->st.st_ex_uid;
4778         acl_wrapper.group = smb_fname->st.st_ex_gid;
4779         acl_wrapper.mode = smb_fname->st.st_ex_mode;
4780
4781         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(blob, mem_ctx,
4782                                                           &acl_wrapper,
4783                                                           (ndr_push_flags_fn_t)ndr_push_smb_acl_wrapper))) {
4784                 errno = EINVAL;
4785                 TALLOC_FREE(frame);
4786                 return -1;
4787         }
4788
4789         *blob_description = talloc_strdup(mem_ctx, "posix_acl");
4790         if (!*blob_description) {
4791                 errno = EINVAL;
4792                 TALLOC_FREE(frame);
4793                 return -1;
4794         }
4795
4796         TALLOC_FREE(frame);
4797         return 0;
4798 }
4799
4800 int posix_sys_acl_blob_get_fd(vfs_handle_struct *handle,
4801                               files_struct *fsp,
4802                               TALLOC_CTX *mem_ctx,
4803                               char **blob_description,
4804                               DATA_BLOB *blob)
4805 {
4806         SMB_STRUCT_STAT sbuf;
4807         TALLOC_CTX *frame;
4808         struct smb_acl_wrapper acl_wrapper;
4809         int ret;
4810
4811         /* This ensures that we also consider the default ACL */
4812         if (fsp->is_directory ||  fsp->fh->fd == -1) {
4813                 return posix_sys_acl_blob_get_file(handle, fsp->fsp_name->base_name,
4814                                                    mem_ctx, blob_description, blob);
4815         }
4816         frame = talloc_stackframe();
4817
4818         acl_wrapper.default_acl = NULL;
4819
4820         acl_wrapper.access_acl = smb_vfs_call_sys_acl_get_file(handle, fsp->fsp_name->base_name,
4821                                                                SMB_ACL_TYPE_ACCESS, frame);
4822
4823         ret = smb_vfs_call_fstat(handle, fsp, &sbuf);
4824         if (ret == -1) {
4825                 TALLOC_FREE(frame);
4826                 return -1;
4827         }
4828
4829         acl_wrapper.owner = sbuf.st_ex_uid;
4830         acl_wrapper.group = sbuf.st_ex_gid;
4831         acl_wrapper.mode = sbuf.st_ex_mode;
4832
4833         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(blob, mem_ctx,
4834                                                           &acl_wrapper,
4835                                                           (ndr_push_flags_fn_t)ndr_push_smb_acl_wrapper))) {
4836                 errno = EINVAL;
4837                 TALLOC_FREE(frame);
4838                 return -1;
4839         }
4840
4841         *blob_description = talloc_strdup(mem_ctx, "posix_acl");
4842         if (!*blob_description) {
4843                 errno = EINVAL;
4844                 TALLOC_FREE(frame);
4845                 return -1;
4846         }
4847
4848         TALLOC_FREE(frame);
4849         return 0;
4850 }