s3-privs Convert from user_has_privileges() -> security_token_has_privilege()
[ira/wip.git] / source3 / smbd / posix_acls.c
1 /*
2    Unix SMB/CIFS implementation.
3    SMB NT Security Descriptor / Unix permission conversion.
4    Copyright (C) Jeremy Allison 1994-2009.
5    Copyright (C) Andreas Gruenbacher 2002.
6    Copyright (C) Simo Sorce <idra@samba.org> 2009.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23
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 = security_token_has_privilege(get_current_nttok(conn), SEC_PRIV_TAKE_OWNERSHIP);
3551                 bool has_restore_priv = security_token_has_privilege(get_current_nttok(conn), SEC_PRIV_RESTORE);
3552
3553                 /* Case (2) */
3554                 if ( ( has_take_ownership_priv && ( uid == get_current_uid(conn) ) ) ||
3555                 /* Case (3) */
3556                      ( has_restore_priv ) ) {
3557
3558                         become_root();
3559                         /* Keep the current file gid the same - take ownership doesn't imply group change. */
3560                         if (lp_posix_pathnames()) {
3561                                 ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid,
3562                                                     (gid_t)-1);
3563                         } else {
3564                                 ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid,
3565                                                     (gid_t)-1);
3566                         }
3567                         unbecome_root();
3568                         return ret;
3569                 }
3570         }
3571
3572         /* Case (4). */
3573         if (!lp_dos_filemode(SNUM(conn))) {
3574                 errno = EPERM;
3575                 return -1;
3576         }
3577
3578         /* only allow chown to the current user. This is more secure,
3579            and also copes with the case where the SID in a take ownership ACL is
3580            a local SID on the users workstation
3581         */
3582         if (uid != get_current_uid(conn)) {
3583                 errno = EPERM;
3584                 return -1;
3585         }
3586
3587         if (lp_posix_pathnames()) {
3588                 ret = SMB_VFS_LSTAT(conn, smb_fname);
3589         } else {
3590                 ret = SMB_VFS_STAT(conn, smb_fname);
3591         }
3592
3593         if (ret == -1) {
3594                 return -1;
3595         }
3596
3597         if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname, &fsp))) {
3598                 return -1;
3599         }
3600
3601         become_root();
3602         /* Keep the current file gid the same. */
3603         if (fsp->fh->fd == -1) {
3604                 if (lp_posix_pathnames()) {
3605                         ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid,
3606                                             (gid_t)-1);
3607                 } else {
3608                         ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid,
3609                                             (gid_t)-1);
3610                 }
3611         } else {
3612                 ret = SMB_VFS_FCHOWN(fsp, uid, (gid_t)-1);
3613         }
3614         unbecome_root();
3615
3616         close_file_fchmod(NULL, fsp);
3617
3618         return ret;
3619 }
3620
3621 #if 0
3622 /* Disable this - prevents ACL inheritance from the ACL editor. JRA. */
3623
3624 /****************************************************************************
3625  Take care of parent ACL inheritance.
3626 ****************************************************************************/
3627
3628 NTSTATUS append_parent_acl(files_struct *fsp,
3629                                 const struct security_descriptor *pcsd,
3630                                 struct security_descriptor **pp_new_sd)
3631 {
3632         struct smb_filename *smb_dname = NULL;
3633         struct security_descriptor *parent_sd = NULL;
3634         files_struct *parent_fsp = NULL;
3635         TALLOC_CTX *mem_ctx = talloc_tos();
3636         char *parent_name = NULL;
3637         struct security_ace *new_ace = NULL;
3638         unsigned int num_aces = pcsd->dacl->num_aces;
3639         NTSTATUS status;
3640         int info;
3641         unsigned int i, j;
3642         struct security_descriptor *psd = dup_sec_desc(talloc_tos(), pcsd);
3643         bool is_dacl_protected = (pcsd->type & SEC_DESC_DACL_PROTECTED);
3644
3645         if (psd == NULL) {
3646                 return NT_STATUS_NO_MEMORY;
3647         }
3648
3649         if (!parent_dirname(mem_ctx, fsp->fsp_name->base_name, &parent_name,
3650                             NULL)) {
3651                 return NT_STATUS_NO_MEMORY;
3652         }
3653
3654         status = create_synthetic_smb_fname(mem_ctx, parent_name, NULL, NULL,
3655                                             &smb_dname);
3656         if (!NT_STATUS_IS_OK(status)) {
3657                 goto fail;
3658         }
3659
3660         status = SMB_VFS_CREATE_FILE(
3661                 fsp->conn,                              /* conn */
3662                 NULL,                                   /* req */
3663                 0,                                      /* root_dir_fid */
3664                 smb_dname,                              /* fname */
3665                 FILE_READ_ATTRIBUTES,                   /* access_mask */
3666                 FILE_SHARE_NONE,                        /* share_access */
3667                 FILE_OPEN,                              /* create_disposition*/
3668                 FILE_DIRECTORY_FILE,                    /* create_options */
3669                 0,                                      /* file_attributes */
3670                 INTERNAL_OPEN_ONLY,                     /* oplock_request */
3671                 0,                                      /* allocation_size */
3672                 NULL,                                   /* sd */
3673                 NULL,                                   /* ea_list */
3674                 &parent_fsp,                            /* result */
3675                 &info);                                 /* pinfo */
3676
3677         if (!NT_STATUS_IS_OK(status)) {
3678                 TALLOC_FREE(smb_dname);
3679                 return status;
3680         }
3681
3682         status = SMB_VFS_GET_NT_ACL(parent_fsp->conn, smb_dname->base_name,
3683                                     SECINFO_DACL, &parent_sd );
3684
3685         close_file(NULL, parent_fsp, NORMAL_CLOSE);
3686         TALLOC_FREE(smb_dname);
3687
3688         if (!NT_STATUS_IS_OK(status)) {
3689                 return status;
3690         }
3691
3692         /*
3693          * Make room for potentially all the ACLs from
3694          * the parent. We used to add the ugw triple here,
3695          * as we knew we were dealing with POSIX ACLs.
3696          * We no longer need to do so as we can guarentee
3697          * that a default ACL from the parent directory will
3698          * be well formed for POSIX ACLs if it came from a
3699          * POSIX ACL source, and if we're not writing to a
3700          * POSIX ACL sink then we don't care if it's not well
3701          * formed. JRA.
3702          */
3703
3704         num_aces += parent_sd->dacl->num_aces;
3705
3706         if((new_ace = TALLOC_ZERO_ARRAY(mem_ctx, struct security_ace,
3707                                         num_aces)) == NULL) {
3708                 return NT_STATUS_NO_MEMORY;
3709         }
3710
3711         /* Start by copying in all the given ACE entries. */
3712         for (i = 0; i < psd->dacl->num_aces; i++) {
3713                 sec_ace_copy(&new_ace[i], &psd->dacl->aces[i]);
3714         }
3715
3716         /*
3717          * Note that we're ignoring "inherit permissions" here
3718          * as that really only applies to newly created files. JRA.
3719          */
3720
3721         /* Finally append any inherited ACEs. */
3722         for (j = 0; j < parent_sd->dacl->num_aces; j++) {
3723                 struct security_ace *se = &parent_sd->dacl->aces[j];
3724
3725                 if (fsp->is_directory) {
3726                         if (!(se->flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
3727                                 /* Doesn't apply to a directory - ignore. */
3728                                 DEBUG(10,("append_parent_acl: directory %s "
3729                                         "ignoring non container "
3730                                         "inherit flags %u on ACE with sid %s "
3731                                         "from parent %s\n",
3732                                         fsp_str_dbg(fsp),
3733                                         (unsigned int)se->flags,
3734                                         sid_string_dbg(&se->trustee),
3735                                         parent_name));
3736                                 continue;
3737                         }
3738                 } else {
3739                         if (!(se->flags & SEC_ACE_FLAG_OBJECT_INHERIT)) {
3740                                 /* Doesn't apply to a file - ignore. */
3741                                 DEBUG(10,("append_parent_acl: file %s "
3742                                         "ignoring non object "
3743                                         "inherit flags %u on ACE with sid %s "
3744                                         "from parent %s\n",
3745                                         fsp_str_dbg(fsp),
3746                                         (unsigned int)se->flags,
3747                                         sid_string_dbg(&se->trustee),
3748                                         parent_name));
3749                                 continue;
3750                         }
3751                 }
3752
3753                 if (is_dacl_protected) {
3754                         /* If the DACL is protected it means we must
3755                          * not overwrite an existing ACE entry with the
3756                          * same SID. This is order N^2. Ouch :-(. JRA. */
3757                         unsigned int k;
3758                         for (k = 0; k < psd->dacl->num_aces; k++) {
3759                                 if (sid_equal(&psd->dacl->aces[k].trustee,
3760                                                 &se->trustee)) {
3761                                         break;
3762                                 }
3763                         }
3764                         if (k < psd->dacl->num_aces) {
3765                                 /* SID matched. Ignore. */
3766                                 DEBUG(10,("append_parent_acl: path %s "
3767                                         "ignoring ACE with protected sid %s "
3768                                         "from parent %s\n",
3769                                         fsp_str_dbg(fsp),
3770                                         sid_string_dbg(&se->trustee),
3771                                         parent_name));
3772                                 continue;
3773                         }
3774                 }
3775
3776                 sec_ace_copy(&new_ace[i], se);
3777                 if (se->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
3778                         new_ace[i].flags &= ~(SEC_ACE_FLAG_VALID_INHERIT);
3779                 }
3780                 new_ace[i].flags |= SEC_ACE_FLAG_INHERITED_ACE;
3781
3782                 if (fsp->is_directory) {
3783                         /*
3784                          * Strip off any inherit only. It's applied.
3785                          */
3786                         new_ace[i].flags &= ~(SEC_ACE_FLAG_INHERIT_ONLY);
3787                         if (se->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
3788                                 /* No further inheritance. */
3789                                 new_ace[i].flags &=
3790                                         ~(SEC_ACE_FLAG_CONTAINER_INHERIT|
3791                                         SEC_ACE_FLAG_OBJECT_INHERIT);
3792                         }
3793                 } else {
3794                         /*
3795                          * Strip off any container or inherit
3796                          * flags, they can't apply to objects.
3797                          */
3798                         new_ace[i].flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|
3799                                                 SEC_ACE_FLAG_INHERIT_ONLY|
3800                                                 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT);
3801                 }
3802                 i++;
3803
3804                 DEBUG(10,("append_parent_acl: path %s "
3805                         "inheriting ACE with sid %s "
3806                         "from parent %s\n",
3807                         fsp_str_dbg(fsp),
3808                         sid_string_dbg(&se->trustee),
3809                         parent_name));
3810         }
3811
3812         psd->dacl->aces = new_ace;
3813         psd->dacl->num_aces = i;
3814         psd->type &= ~(SEC_DESC_DACL_AUTO_INHERITED|
3815                          SEC_DESC_DACL_AUTO_INHERIT_REQ);
3816
3817         *pp_new_sd = psd;
3818         return status;
3819 }
3820 #endif
3821
3822 /****************************************************************************
3823  Reply to set a security descriptor on an fsp. security_info_sent is the
3824  description of the following NT ACL.
3825  This should be the only external function needed for the UNIX style set ACL.
3826 ****************************************************************************/
3827
3828 NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd)
3829 {
3830         connection_struct *conn = fsp->conn;
3831         uid_t user = (uid_t)-1;
3832         gid_t grp = (gid_t)-1;
3833         struct dom_sid file_owner_sid;
3834         struct dom_sid file_grp_sid;
3835         canon_ace *file_ace_list = NULL;
3836         canon_ace *dir_ace_list = NULL;
3837         bool acl_perms = False;
3838         mode_t orig_mode = (mode_t)0;
3839         NTSTATUS status;
3840         bool set_acl_as_root = false;
3841         bool acl_set_support = false;
3842         bool ret = false;
3843
3844         DEBUG(10,("set_nt_acl: called for file %s\n",
3845                   fsp_str_dbg(fsp)));
3846
3847         if (!CAN_WRITE(conn)) {
3848                 DEBUG(10,("set acl rejected on read-only share\n"));
3849                 return NT_STATUS_MEDIA_WRITE_PROTECTED;
3850         }
3851
3852         /*
3853          * Get the current state of the file.
3854          */
3855
3856         status = vfs_stat_fsp(fsp);
3857         if (!NT_STATUS_IS_OK(status)) {
3858                 return status;
3859         }
3860
3861         /* Save the original element we check against. */
3862         orig_mode = fsp->fsp_name->st.st_ex_mode;
3863
3864         /*
3865          * Unpack the user/group/world id's.
3866          */
3867
3868         status = unpack_nt_owners( conn, &user, &grp, security_info_sent, psd);
3869         if (!NT_STATUS_IS_OK(status)) {
3870                 return status;
3871         }
3872
3873         /*
3874          * Do we need to chown ? If so this must be done first as the incoming
3875          * CREATOR_OWNER acl will be relative to the *new* owner, not the old.
3876          * Noticed by Simo.
3877          */
3878
3879         if (((user != (uid_t)-1) && (fsp->fsp_name->st.st_ex_uid != user)) ||
3880             (( grp != (gid_t)-1) && (fsp->fsp_name->st.st_ex_gid != grp))) {
3881
3882                 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3883                          fsp_str_dbg(fsp), (unsigned int)user,
3884                          (unsigned int)grp));
3885
3886                 if(try_chown(fsp->conn, fsp->fsp_name, user, grp) == -1) {
3887                         DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error "
3888                                  "= %s.\n", fsp_str_dbg(fsp),
3889                                  (unsigned int)user, (unsigned int)grp,
3890                                  strerror(errno)));
3891                         if (errno == EPERM) {
3892                                 return NT_STATUS_INVALID_OWNER;
3893                         }
3894                         return map_nt_error_from_unix(errno);
3895                 }
3896
3897                 /*
3898                  * Recheck the current state of the file, which may have changed.
3899                  * (suid/sgid bits, for instance)
3900                  */
3901
3902                 status = vfs_stat_fsp(fsp);
3903                 if (!NT_STATUS_IS_OK(status)) {
3904                         return status;
3905                 }
3906
3907                 /* Save the original element we check against. */
3908                 orig_mode = fsp->fsp_name->st.st_ex_mode;
3909
3910                 /* If we successfully chowned, we know we must
3911                  * be able to set the acl, so do it as root.
3912                  */
3913                 set_acl_as_root = true;
3914         }
3915
3916         create_file_sids(&fsp->fsp_name->st, &file_owner_sid, &file_grp_sid);
3917
3918         acl_perms = unpack_canon_ace(fsp, &fsp->fsp_name->st, &file_owner_sid,
3919                                      &file_grp_sid, &file_ace_list,
3920                                      &dir_ace_list, security_info_sent, psd);
3921
3922         /* Ignore W2K traverse DACL set. */
3923         if (!file_ace_list && !dir_ace_list) {
3924                 return NT_STATUS_OK;
3925         }
3926
3927         if (!acl_perms) {
3928                 DEBUG(3,("set_nt_acl: cannot set permissions\n"));
3929                 free_canon_ace_list(file_ace_list);
3930                 free_canon_ace_list(dir_ace_list);
3931                 return NT_STATUS_ACCESS_DENIED;
3932         }
3933
3934         /*
3935          * Only change security if we got a DACL.
3936          */
3937
3938         if(!(security_info_sent & SECINFO_DACL) || (psd->dacl == NULL)) {
3939                 free_canon_ace_list(file_ace_list);
3940                 free_canon_ace_list(dir_ace_list);
3941                 return NT_STATUS_OK;
3942         }
3943
3944         /*
3945          * Try using the POSIX ACL set first. Fall back to chmod if
3946          * we have no ACL support on this filesystem.
3947          */
3948
3949         if (acl_perms && file_ace_list) {
3950                 if (set_acl_as_root) {
3951                         become_root();
3952                 }
3953                 ret = set_canon_ace_list(fsp, file_ace_list, false,
3954                                          &fsp->fsp_name->st, &acl_set_support);
3955                 if (set_acl_as_root) {
3956                         unbecome_root();
3957                 }
3958                 if (acl_set_support && ret == false) {
3959                         DEBUG(3,("set_nt_acl: failed to set file acl on file "
3960                                  "%s (%s).\n", fsp_str_dbg(fsp),
3961                                  strerror(errno)));
3962                         free_canon_ace_list(file_ace_list);
3963                         free_canon_ace_list(dir_ace_list);
3964                         return map_nt_error_from_unix(errno);
3965                 }
3966         }
3967
3968         if (acl_perms && acl_set_support && fsp->is_directory) {
3969                 if (dir_ace_list) {
3970                         if (set_acl_as_root) {
3971                                 become_root();
3972                         }
3973                         ret = set_canon_ace_list(fsp, dir_ace_list, true,
3974                                                  &fsp->fsp_name->st,
3975                                                  &acl_set_support);
3976                         if (set_acl_as_root) {
3977                                 unbecome_root();
3978                         }
3979                         if (ret == false) {
3980                                 DEBUG(3,("set_nt_acl: failed to set default "
3981                                          "acl on directory %s (%s).\n",
3982                                          fsp_str_dbg(fsp), strerror(errno)));
3983                                 free_canon_ace_list(file_ace_list);
3984                                 free_canon_ace_list(dir_ace_list);
3985                                 return map_nt_error_from_unix(errno);
3986                         }
3987                 } else {
3988                         int sret = -1;
3989
3990                         /*
3991                          * No default ACL - delete one if it exists.
3992                          */
3993
3994                         if (set_acl_as_root) {
3995                                 become_root();
3996                         }
3997                         sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn,
3998                             fsp->fsp_name->base_name);
3999                         if (set_acl_as_root) {
4000                                 unbecome_root();
4001                         }
4002                         if (sret == -1) {
4003                                 if (acl_group_override(conn, fsp->fsp_name)) {
4004                                         DEBUG(5,("set_nt_acl: acl group "
4005                                                  "control on and current user "
4006                                                  "in file %s primary group. "
4007                                                  "Override delete_def_acl\n",
4008                                                  fsp_str_dbg(fsp)));
4009
4010                                         become_root();
4011                                         sret =
4012                                             SMB_VFS_SYS_ACL_DELETE_DEF_FILE(
4013                                                     conn,
4014                                                     fsp->fsp_name->base_name);
4015                                         unbecome_root();
4016                                 }
4017
4018                                 if (sret == -1) {
4019                                         DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
4020                                         free_canon_ace_list(file_ace_list);
4021                                         free_canon_ace_list(dir_ace_list);
4022                                         return map_nt_error_from_unix(errno);
4023                                 }
4024                         }
4025                 }
4026         }
4027
4028         if (acl_set_support) {
4029                 if (set_acl_as_root) {
4030                         become_root();
4031                 }
4032                 store_inheritance_attributes(fsp,
4033                                 file_ace_list,
4034                                 dir_ace_list,
4035                                 psd->type);
4036                 if (set_acl_as_root) {
4037                         unbecome_root();
4038                 }
4039         }
4040
4041         /*
4042          * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
4043          */
4044
4045         if(!acl_set_support && acl_perms) {
4046                 mode_t posix_perms;
4047
4048                 if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
4049                         free_canon_ace_list(file_ace_list);
4050                         free_canon_ace_list(dir_ace_list);
4051                         DEBUG(3,("set_nt_acl: failed to convert file acl to "
4052                                  "posix permissions for file %s.\n",
4053                                  fsp_str_dbg(fsp)));
4054                         return NT_STATUS_ACCESS_DENIED;
4055                 }
4056
4057                 if (orig_mode != posix_perms) {
4058                         int sret = -1;
4059
4060                         DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
4061                                  fsp_str_dbg(fsp), (unsigned int)posix_perms));
4062
4063                         if (set_acl_as_root) {
4064                                 become_root();
4065                         }
4066                         sret = SMB_VFS_CHMOD(conn, fsp->fsp_name->base_name,
4067                                              posix_perms);
4068                         if (set_acl_as_root) {
4069                                 unbecome_root();
4070                         }
4071                         if(sret == -1) {
4072                                 if (acl_group_override(conn, fsp->fsp_name)) {
4073                                         DEBUG(5,("set_nt_acl: acl group "
4074                                                  "control on and current user "
4075                                                  "in file %s primary group. "
4076                                                  "Override chmod\n",
4077                                                  fsp_str_dbg(fsp)));
4078
4079                                         become_root();
4080                                         sret = SMB_VFS_CHMOD(conn,
4081                                             fsp->fsp_name->base_name,
4082                                             posix_perms);
4083                                         unbecome_root();
4084                                 }
4085
4086                                 if (sret == -1) {
4087                                         DEBUG(3,("set_nt_acl: chmod %s, 0%o "
4088                                                  "failed. Error = %s.\n",
4089                                                  fsp_str_dbg(fsp),
4090                                                  (unsigned int)posix_perms,
4091                                                  strerror(errno)));
4092                                         free_canon_ace_list(file_ace_list);
4093                                         free_canon_ace_list(dir_ace_list);
4094                                         return map_nt_error_from_unix(errno);
4095                                 }
4096                         }
4097                 }
4098         }
4099
4100         free_canon_ace_list(file_ace_list);
4101         free_canon_ace_list(dir_ace_list);
4102
4103         /* Ensure the stat struct in the fsp is correct. */
4104         status = vfs_stat_fsp(fsp);
4105
4106         return NT_STATUS_OK;
4107 }
4108
4109 /****************************************************************************
4110  Get the actual group bits stored on a file with an ACL. Has no effect if
4111  the file has no ACL. Needed in dosmode code where the stat() will return
4112  the mask bits, not the real group bits, for a file with an ACL.
4113 ****************************************************************************/
4114
4115 int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode )
4116 {
4117         int entry_id = SMB_ACL_FIRST_ENTRY;
4118         SMB_ACL_ENTRY_T entry;
4119         SMB_ACL_T posix_acl;
4120         int result = -1;
4121
4122         posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
4123         if (posix_acl == (SMB_ACL_T)NULL)
4124                 return -1;
4125
4126         while (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
4127                 SMB_ACL_TAG_T tagtype;
4128                 SMB_ACL_PERMSET_T permset;
4129
4130                 entry_id = SMB_ACL_NEXT_ENTRY;
4131
4132                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) ==-1)
4133                         break;
4134
4135                 if (tagtype == SMB_ACL_GROUP_OBJ) {
4136                         if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
4137                                 break;
4138                         } else {
4139                                 *mode &= ~(S_IRGRP|S_IWGRP|S_IXGRP);
4140                                 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRGRP : 0);
4141                                 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWGRP : 0);
4142                                 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0);
4143                                 result = 0;
4144                                 break;
4145                         }
4146                 }
4147         }
4148         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
4149         return result;
4150 }
4151
4152 /****************************************************************************
4153  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
4154  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
4155 ****************************************************************************/
4156
4157 static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode)
4158 {
4159         int entry_id = SMB_ACL_FIRST_ENTRY;
4160         SMB_ACL_ENTRY_T entry;
4161         int num_entries = 0;
4162
4163         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
4164                 SMB_ACL_TAG_T tagtype;
4165                 SMB_ACL_PERMSET_T permset;
4166                 mode_t perms;
4167
4168                 entry_id = SMB_ACL_NEXT_ENTRY;
4169
4170                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
4171                         return -1;
4172
4173                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
4174                         return -1;
4175
4176                 num_entries++;
4177
4178                 switch(tagtype) {
4179                         case SMB_ACL_USER_OBJ:
4180                                 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
4181                                 break;
4182                         case SMB_ACL_GROUP_OBJ:
4183                                 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
4184                                 break;
4185                         case SMB_ACL_MASK:
4186                                 /*
4187                                  * FIXME: The ACL_MASK entry permissions should really be set to
4188                                  * the union of the permissions of all ACL_USER,
4189                                  * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
4190                                  * acl_calc_mask() does, but Samba ACLs doesn't provide it.
4191                                  */
4192                                 perms = S_IRUSR|S_IWUSR|S_IXUSR;
4193                                 break;
4194                         case SMB_ACL_OTHER:
4195                                 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
4196                                 break;
4197                         default:
4198                                 continue;
4199                 }
4200
4201                 if (map_acl_perms_to_permset(conn, perms, &permset) == -1)
4202                         return -1;
4203
4204                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1)
4205                         return -1;
4206         }
4207
4208         /*
4209          * If this is a simple 3 element ACL or no elements then it's a standard
4210          * UNIX permission set. Just use chmod...       
4211          */
4212
4213         if ((num_entries == 3) || (num_entries == 0))
4214                 return -1;
4215
4216         return 0;
4217 }
4218
4219 /****************************************************************************
4220  Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
4221  GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
4222  resulting ACL on TO.  Note that name is in UNIX character set.
4223 ****************************************************************************/
4224
4225 static int copy_access_posix_acl(connection_struct *conn, const char *from, const char *to, mode_t mode)
4226 {
4227         SMB_ACL_T posix_acl = NULL;
4228         int ret = -1;
4229
4230         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL)
4231                 return -1;
4232
4233         if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
4234                 goto done;
4235
4236         ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl);
4237
4238  done:
4239
4240         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
4241         return ret;
4242 }
4243
4244 /****************************************************************************
4245  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
4246  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
4247  Note that name is in UNIX character set.
4248 ****************************************************************************/
4249
4250 int chmod_acl(connection_struct *conn, const char *name, mode_t mode)
4251 {
4252         return copy_access_posix_acl(conn, name, name, mode);
4253 }
4254
4255 /****************************************************************************
4256  Check for an existing default POSIX ACL on a directory.
4257 ****************************************************************************/
4258
4259 static bool directory_has_default_posix_acl(connection_struct *conn, const char *fname)
4260 {
4261         SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
4262         bool has_acl = False;
4263         SMB_ACL_ENTRY_T entry;
4264
4265         if (def_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) {
4266                 has_acl = True;
4267         }
4268
4269         if (def_acl) {
4270                 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4271         }
4272         return has_acl;
4273 }
4274
4275 /****************************************************************************
4276  If the parent directory has no default ACL but it does have an Access ACL,
4277  inherit this Access ACL to file name.
4278 ****************************************************************************/
4279
4280 int inherit_access_posix_acl(connection_struct *conn, const char *inherit_from_dir,
4281                        const char *name, mode_t mode)
4282 {
4283         if (directory_has_default_posix_acl(conn, inherit_from_dir))
4284                 return 0;
4285
4286         return copy_access_posix_acl(conn, inherit_from_dir, name, mode);
4287 }
4288
4289 /****************************************************************************
4290  Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
4291  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
4292 ****************************************************************************/
4293
4294 int fchmod_acl(files_struct *fsp, mode_t mode)
4295 {
4296         connection_struct *conn = fsp->conn;
4297         SMB_ACL_T posix_acl = NULL;
4298         int ret = -1;
4299
4300         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp)) == NULL)
4301                 return -1;
4302
4303         if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
4304                 goto done;
4305
4306         ret = SMB_VFS_SYS_ACL_SET_FD(fsp, posix_acl);
4307
4308   done:
4309
4310         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
4311         return ret;
4312 }
4313
4314 /****************************************************************************
4315  Map from wire type to permset.
4316 ****************************************************************************/
4317
4318 static bool unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_perm, SMB_ACL_PERMSET_T *p_permset)
4319 {
4320         if (wire_perm & ~(SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE)) {
4321                 return False;
4322         }
4323
4324         if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) ==  -1) {
4325                 return False;
4326         }
4327
4328         if (wire_perm & SMB_POSIX_ACL_READ) {
4329                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1) {
4330                         return False;
4331                 }
4332         }
4333         if (wire_perm & SMB_POSIX_ACL_WRITE) {
4334                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1) {
4335                         return False;
4336                 }
4337         }
4338         if (wire_perm & SMB_POSIX_ACL_EXECUTE) {
4339                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1) {
4340                         return False;
4341                 }
4342         }
4343         return True;
4344 }
4345
4346 /****************************************************************************
4347  Map from wire type to tagtype.
4348 ****************************************************************************/
4349
4350 static bool unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt)
4351 {
4352         switch (wire_tt) {
4353                 case SMB_POSIX_ACL_USER_OBJ:
4354                         *p_tt = SMB_ACL_USER_OBJ;
4355                         break;
4356                 case SMB_POSIX_ACL_USER:
4357                         *p_tt = SMB_ACL_USER;
4358                         break;
4359                 case SMB_POSIX_ACL_GROUP_OBJ:
4360                         *p_tt = SMB_ACL_GROUP_OBJ;
4361                         break;
4362                 case SMB_POSIX_ACL_GROUP:
4363                         *p_tt = SMB_ACL_GROUP;
4364                         break;
4365                 case SMB_POSIX_ACL_MASK:
4366                         *p_tt = SMB_ACL_MASK;
4367                         break;
4368                 case SMB_POSIX_ACL_OTHER:
4369                         *p_tt = SMB_ACL_OTHER;
4370                         break;
4371                 default:
4372                         return False;
4373         }
4374         return True;
4375 }
4376
4377 /****************************************************************************
4378  Create a new POSIX acl from wire permissions.
4379  FIXME ! How does the share mask/mode fit into this.... ?
4380 ****************************************************************************/
4381
4382 static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_acls, const char *pdata)
4383 {
4384         unsigned int i;
4385         SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, num_acls);
4386
4387         if (the_acl == NULL) {
4388                 return NULL;
4389         }
4390
4391         for (i = 0; i < num_acls; i++) {
4392                 SMB_ACL_ENTRY_T the_entry;
4393                 SMB_ACL_PERMSET_T the_permset;
4394                 SMB_ACL_TAG_T tag_type;
4395
4396                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
4397                         DEBUG(0,("create_posix_acl_from_wire: Failed to create entry %u. (%s)\n",
4398                                 i, strerror(errno) ));
4399                         goto fail;
4400                 }
4401
4402                 if (!unix_ex_wire_to_tagtype(CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), &tag_type)) {
4403                         DEBUG(0,("create_posix_acl_from_wire: invalid wire tagtype %u on entry %u.\n",
4404                                 CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), i ));
4405                         goto fail;
4406                 }
4407
4408                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, tag_type) == -1) {
4409                         DEBUG(0,("create_posix_acl_from_wire: Failed to set tagtype on entry %u. (%s)\n",
4410                                 i, strerror(errno) ));
4411                         goto fail;
4412                 }
4413
4414                 /* Get the permset pointer from the new ACL entry. */
4415                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
4416                         DEBUG(0,("create_posix_acl_from_wire: Failed to get permset on entry %u. (%s)\n",
4417                                 i, strerror(errno) ));
4418                         goto fail;
4419                 }
4420
4421                 /* Map from wire to permissions. */
4422                 if (!unix_ex_wire_to_permset(conn, CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+1), &the_permset)) {
4423                         DEBUG(0,("create_posix_acl_from_wire: invalid permset %u on entry %u.\n",
4424                                 CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE) + 1), i ));
4425                         goto fail;
4426                 }
4427
4428                 /* Now apply to the new ACL entry. */
4429                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
4430                         DEBUG(0,("create_posix_acl_from_wire: Failed to add permset on entry %u. (%s)\n",
4431                                 i, strerror(errno) ));
4432                         goto fail;
4433                 }
4434
4435                 if (tag_type == SMB_ACL_USER) {
4436                         uint32 uidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
4437                         uid_t uid = (uid_t)uidval;
4438                         if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&uid) == -1) {
4439                                 DEBUG(0,("create_posix_acl_from_wire: Failed to set uid %u on entry %u. (%s)\n",
4440                                         (unsigned int)uid, i, strerror(errno) ));
4441                                 goto fail;
4442                         }
4443                 }
4444
4445                 if (tag_type == SMB_ACL_GROUP) {
4446                         uint32 gidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
4447                         gid_t gid = (uid_t)gidval;
4448                         if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&gid) == -1) {
4449                                 DEBUG(0,("create_posix_acl_from_wire: Failed to set gid %u on entry %u. (%s)\n",
4450                                         (unsigned int)gid, i, strerror(errno) ));
4451                                 goto fail;
4452                         }
4453                 }
4454         }
4455
4456         return the_acl;
4457
4458  fail:
4459
4460         if (the_acl != NULL) {
4461                 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
4462         }
4463         return NULL;
4464 }
4465
4466 /****************************************************************************
4467  Calls from UNIX extensions - Default POSIX ACL set.
4468  If num_def_acls == 0 and not a directory just return. If it is a directory
4469  and num_def_acls == 0 then remove the default acl. Else set the default acl
4470  on the directory.
4471 ****************************************************************************/
4472
4473 bool set_unix_posix_default_acl(connection_struct *conn, const char *fname, const SMB_STRUCT_STAT *psbuf,
4474                                 uint16 num_def_acls, const char *pdata)
4475 {
4476         SMB_ACL_T def_acl = NULL;
4477
4478         if (!S_ISDIR(psbuf->st_ex_mode)) {
4479                 if (num_def_acls) {
4480                         DEBUG(5,("set_unix_posix_default_acl: Can't set default ACL on non-directory file %s\n", fname ));
4481                         errno = EISDIR;
4482                         return False;
4483                 } else {
4484                         return True;
4485                 }
4486         }
4487
4488         if (!num_def_acls) {
4489                 /* Remove the default ACL. */
4490                 if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fname) == -1) {
4491                         DEBUG(5,("set_unix_posix_default_acl: acl_delete_def_file failed on directory %s (%s)\n",
4492                                 fname, strerror(errno) ));
4493                         return False;
4494                 }
4495                 return True;
4496         }
4497
4498         if ((def_acl = create_posix_acl_from_wire(conn, num_def_acls, pdata)) == NULL) {
4499                 return False;
4500         }
4501
4502         if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT, def_acl) == -1) {
4503                 DEBUG(5,("set_unix_posix_default_acl: acl_set_file failed on directory %s (%s)\n",
4504                         fname, strerror(errno) ));
4505                 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4506                 return False;
4507         }
4508
4509         DEBUG(10,("set_unix_posix_default_acl: set default acl for file %s\n", fname ));
4510         SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4511         return True;
4512 }
4513
4514 /****************************************************************************
4515  Remove an ACL from a file. As we don't have acl_delete_entry() available
4516  we must read the current acl and copy all entries except MASK, USER and GROUP
4517  to a new acl, then set that. This (at least on Linux) causes any ACL to be
4518  removed.
4519  FIXME ! How does the share mask/mode fit into this.... ?
4520 ****************************************************************************/
4521
4522 static bool remove_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname)
4523 {
4524         SMB_ACL_T file_acl = NULL;
4525         int entry_id = SMB_ACL_FIRST_ENTRY;
4526         SMB_ACL_ENTRY_T entry;
4527         bool ret = False;
4528         /* Create a new ACL with only 3 entries, u/g/w. */
4529         SMB_ACL_T new_file_acl = SMB_VFS_SYS_ACL_INIT(conn, 3);
4530         SMB_ACL_ENTRY_T user_ent = NULL;
4531         SMB_ACL_ENTRY_T group_ent = NULL;
4532         SMB_ACL_ENTRY_T other_ent = NULL;
4533
4534         if (new_file_acl == NULL) {
4535                 DEBUG(5,("remove_posix_acl: failed to init new ACL with 3 entries for file %s.\n", fname));
4536                 return False;
4537         }
4538
4539         /* Now create the u/g/w entries. */
4540         if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &user_ent) == -1) {
4541                 DEBUG(5,("remove_posix_acl: Failed to create user entry for file %s. (%s)\n",
4542                         fname, strerror(errno) ));
4543                 goto done;
4544         }
4545         if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, user_ent, SMB_ACL_USER_OBJ) == -1) {
4546                 DEBUG(5,("remove_posix_acl: Failed to set user entry for file %s. (%s)\n",
4547                         fname, strerror(errno) ));
4548                 goto done;
4549         }
4550
4551         if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &group_ent) == -1) {
4552                 DEBUG(5,("remove_posix_acl: Failed to create group entry for file %s. (%s)\n",
4553                         fname, strerror(errno) ));
4554                 goto done;
4555         }
4556         if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, group_ent, SMB_ACL_GROUP_OBJ) == -1) {
4557                 DEBUG(5,("remove_posix_acl: Failed to set group entry for file %s. (%s)\n",
4558                         fname, strerror(errno) ));
4559                 goto done;
4560         }
4561
4562         if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &other_ent) == -1) {
4563                 DEBUG(5,("remove_posix_acl: Failed to create other entry for file %s. (%s)\n",
4564                         fname, strerror(errno) ));
4565                 goto done;
4566         }
4567         if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, other_ent, SMB_ACL_OTHER) == -1) {
4568                 DEBUG(5,("remove_posix_acl: Failed to set other entry for file %s. (%s)\n",
4569                         fname, strerror(errno) ));
4570                 goto done;
4571         }
4572
4573         /* Get the current file ACL. */
4574         if (fsp && fsp->fh->fd != -1) {
4575                 file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp);
4576         } else {
4577                 file_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_ACCESS);
4578         }
4579
4580         if (file_acl == NULL) {
4581                 /* This is only returned if an error occurred. Even for a file with
4582                    no acl a u/g/w acl should be returned. */
4583                 DEBUG(5,("remove_posix_acl: failed to get ACL from file %s (%s).\n",
4584                         fname, strerror(errno) ));
4585                 goto done;
4586         }
4587
4588         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, file_acl, entry_id, &entry) == 1) {
4589                 SMB_ACL_TAG_T tagtype;
4590                 SMB_ACL_PERMSET_T permset;
4591
4592                 entry_id = SMB_ACL_NEXT_ENTRY;
4593
4594                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
4595                         DEBUG(5,("remove_posix_acl: failed to get tagtype from ACL on file %s (%s).\n",
4596                                 fname, strerror(errno) ));
4597                         goto done;
4598                 }
4599
4600                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
4601                         DEBUG(5,("remove_posix_acl: failed to get permset from ACL on file %s (%s).\n",
4602                                 fname, strerror(errno) ));
4603                         goto done;
4604                 }
4605
4606                 if (tagtype == SMB_ACL_USER_OBJ) {
4607                         if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, user_ent, permset) == -1) {
4608                                 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
4609                                         fname, strerror(errno) ));
4610                         }
4611                 } else if (tagtype == SMB_ACL_GROUP_OBJ) {
4612                         if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, group_ent, permset) == -1) {
4613                                 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
4614                                         fname, strerror(errno) ));
4615                         }
4616                 } else if (tagtype == SMB_ACL_OTHER) {
4617                         if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, other_ent, permset) == -1) {
4618                                 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
4619                                         fname, strerror(errno) ));
4620                         }
4621                 }
4622         }
4623
4624         /* Set the new empty file ACL. */
4625         if (fsp && fsp->fh->fd != -1) {
4626                 if (SMB_VFS_SYS_ACL_SET_FD(fsp, new_file_acl) == -1) {
4627                         DEBUG(5,("remove_posix_acl: acl_set_file failed on %s (%s)\n",
4628                                 fname, strerror(errno) ));
4629                         goto done;
4630                 }
4631         } else {
4632                 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, new_file_acl) == -1) {
4633                         DEBUG(5,("remove_posix_acl: acl_set_file failed on %s (%s)\n",
4634                                 fname, strerror(errno) ));
4635                         goto done;
4636                 }
4637         }
4638
4639         ret = True;
4640
4641  done:
4642
4643         if (file_acl) {
4644                 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4645         }
4646         if (new_file_acl) {
4647                 SMB_VFS_SYS_ACL_FREE_ACL(conn, new_file_acl);
4648         }
4649         return ret;
4650 }
4651
4652 /****************************************************************************
4653  Calls from UNIX extensions - POSIX ACL set.
4654  If num_def_acls == 0 then read/modify/write acl after removing all entries
4655  except SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER.
4656 ****************************************************************************/
4657
4658 bool set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname, uint16 num_acls, const char *pdata)
4659 {
4660         SMB_ACL_T file_acl = NULL;
4661
4662         if (!num_acls) {
4663                 /* Remove the ACL from the file. */
4664                 return remove_posix_acl(conn, fsp, fname);
4665         }
4666
4667         if ((file_acl = create_posix_acl_from_wire(conn, num_acls, pdata)) == NULL) {
4668                 return False;
4669         }
4670
4671         if (fsp && fsp->fh->fd != -1) {
4672                 /* The preferred way - use an open fd. */
4673                 if (SMB_VFS_SYS_ACL_SET_FD(fsp, file_acl) == -1) {
4674                         DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
4675                                 fname, strerror(errno) ));
4676                         SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4677                         return False;
4678                 }
4679         } else {
4680                 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, file_acl) == -1) {
4681                         DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
4682                                 fname, strerror(errno) ));
4683                         SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4684                         return False;
4685                 }
4686         }
4687
4688         DEBUG(10,("set_unix_posix_acl: set acl for file %s\n", fname ));
4689         SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4690         return True;
4691 }
4692
4693 /********************************************************************
4694  Pull the NT ACL from a file on disk or the OpenEventlog() access
4695  check.  Caller is responsible for freeing the returned security
4696  descriptor via TALLOC_FREE().  This is designed for dealing with 
4697  user space access checks in smbd outside of the VFS.  For example,
4698  checking access rights in OpenEventlog().
4699
4700  Assume we are dealing with files (for now)
4701 ********************************************************************/
4702
4703 struct security_descriptor *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
4704 {
4705         struct security_descriptor *psd, *ret_sd;
4706         connection_struct *conn;
4707         files_struct finfo;
4708         struct fd_handle fh;
4709         NTSTATUS status;
4710
4711         conn = TALLOC_ZERO_P(ctx, connection_struct);
4712         if (conn == NULL) {
4713                 DEBUG(0, ("talloc failed\n"));
4714                 return NULL;
4715         }
4716
4717         if (!(conn->params = TALLOC_P(conn, struct share_params))) {
4718                 DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n"));
4719                 TALLOC_FREE(conn);
4720                 return NULL;
4721         }
4722
4723         conn->params->service = -1;
4724
4725         set_conn_connectpath(conn, "/");
4726
4727         if (!smbd_vfs_init(conn)) {
4728                 DEBUG(0,("get_nt_acl_no_snum: Unable to create a fake connection struct!\n"));
4729                 conn_free(conn);
4730                 return NULL;
4731         }
4732
4733         ZERO_STRUCT( finfo );
4734         ZERO_STRUCT( fh );
4735
4736         finfo.fnum = -1;
4737         finfo.conn = conn;
4738         finfo.fh = &fh;
4739         finfo.fh->fd = -1;
4740
4741         status = create_synthetic_smb_fname(talloc_tos(), fname, NULL, NULL,
4742                                             &finfo.fsp_name);
4743         if (!NT_STATUS_IS_OK(status)) {
4744                 conn_free(conn);
4745                 return NULL;
4746         }
4747
4748         if (!NT_STATUS_IS_OK(SMB_VFS_FGET_NT_ACL( &finfo, SECINFO_DACL, &psd))) {
4749                 DEBUG(0,("get_nt_acl_no_snum: get_nt_acl returned zero.\n"));
4750                 TALLOC_FREE(finfo.fsp_name);
4751                 conn_free(conn);
4752                 return NULL;
4753         }
4754
4755         ret_sd = dup_sec_desc( ctx, psd );
4756
4757         TALLOC_FREE(finfo.fsp_name);
4758         conn_free(conn);
4759
4760         return ret_sd;
4761 }