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