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