s3:libsmb: allow store_cldap_reply() to work with a ipv6 response
[samba.git] / source3 / modules / nfs4_acls.c
1 /*
2  * NFS4 ACL handling
3  *
4  * Copyright (C) Jim McDonough, 2006
5  * Copyright (C) Christof Schmitt 2019
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "includes.h"
22 #include "smbd/smbd.h"
23 #include "nfs4_acls.h"
24 #include "librpc/gen_ndr/ndr_security.h"
25 #include "librpc/gen_ndr/idmap.h"
26 #include "../libcli/security/dom_sid.h"
27 #include "../libcli/security/security.h"
28 #include "dbwrap/dbwrap.h"
29 #include "dbwrap/dbwrap_open.h"
30 #include "system/filesys.h"
31 #include "passdb/lookup_sid.h"
32 #include "util_tdb.h"
33 #include "lib/param/loadparm.h"
34
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_ACLS
37
38 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
39
40 extern const struct generic_mapping file_generic_mapping;
41
42 struct SMB4ACE_T
43 {
44         SMB_ACE4PROP_T  prop;
45         struct SMB4ACE_T *next;
46 };
47
48 struct SMB4ACL_T
49 {
50         uint16_t controlflags;
51         uint32_t naces;
52         struct SMB4ACE_T        *first;
53         struct SMB4ACE_T        *last;
54 };
55
56 /*
57  * Gather special parameters for NFS4 ACL handling
58  */
59 int smbacl4_get_vfs_params(struct connection_struct *conn,
60                            struct smbacl4_vfs_params *params)
61 {
62         static const struct enum_list enum_smbacl4_modes[] = {
63                 { e_simple, "simple" },
64                 { e_special, "special" },
65                 { -1 , NULL }
66         };
67         static const struct enum_list enum_smbacl4_acedups[] = {
68                 { e_dontcare, "dontcare" },
69                 { e_reject, "reject" },
70                 { e_ignore, "ignore" },
71                 { e_merge, "merge" },
72                 { -1 , NULL }
73         };
74         int enumval;
75
76         *params = (struct smbacl4_vfs_params) { 0 };
77
78         enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "mode",
79                                enum_smbacl4_modes, e_simple);
80         if (enumval == -1) {
81                 DEBUG(10, ("value for %s:mode unknown\n",
82                            SMBACL4_PARAM_TYPE_NAME));
83                 return -1;
84         }
85         params->mode = (enum smbacl4_mode_enum)enumval;
86         if (params->mode == e_special) {
87                 DBG_WARNING("nfs4:mode special is deprecated.\n");
88         }
89
90         params->do_chown = lp_parm_bool(SNUM(conn), SMBACL4_PARAM_TYPE_NAME,
91                 "chown", true);
92
93         enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "acedup",
94                                enum_smbacl4_acedups, e_merge);
95         if (enumval == -1) {
96                 DEBUG(10, ("value for %s:acedup unknown\n",
97                            SMBACL4_PARAM_TYPE_NAME));
98                 return -1;
99         }
100         params->acedup = (enum smbacl4_acedup_enum)enumval;
101         if (params->acedup == e_ignore) {
102                 DBG_WARNING("nfs4:acedup ignore is deprecated.\n");
103         }
104         if (params->acedup == e_reject) {
105                 DBG_WARNING("nfs4:acedup ignore is deprecated.\n");
106         }
107
108         params->map_full_control = lp_acl_map_full_control(SNUM(conn));
109
110         DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
111                 enum_smbacl4_modes[params->mode].name,
112                 params->do_chown ? "true" : "false",
113                 enum_smbacl4_acedups[params->acedup].name,
114                 params->map_full_control ? "true" : "false"));
115
116         return 0;
117 }
118
119 static int fstatat_with_cap_dac_override(int fd,
120                                          const char *pathname,
121                                          SMB_STRUCT_STAT *sbuf,
122                                          int flags,
123                                          bool fake_dir_create_times)
124 {
125         int ret;
126
127         set_effective_capability(DAC_OVERRIDE_CAPABILITY);
128         ret = sys_fstatat(fd,
129                           pathname,
130                           sbuf,
131                           flags,
132                           fake_dir_create_times);
133         drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
134
135         return ret;
136 }
137
138 static int stat_with_cap_dac_override(struct vfs_handle_struct *handle,
139                                       struct smb_filename *smb_fname, int flag)
140 {
141         bool fake_dctime = lp_fake_directory_create_times(SNUM(handle->conn));
142         int fd = -1;
143         NTSTATUS status;
144         struct smb_filename *dir_name = NULL;
145         struct smb_filename *rel_name = NULL;
146         int ret = -1;
147 #ifdef O_PATH
148         int open_flags = O_PATH;
149 #else
150         int open_flags = O_RDONLY;
151 #endif
152
153         status = SMB_VFS_PARENT_PATHNAME(handle->conn,
154                                          talloc_tos(),
155                                          smb_fname,
156                                          &dir_name,
157                                          &rel_name);
158         if (!NT_STATUS_IS_OK(status)) {
159                 errno = map_errno_from_nt_status(status);
160                 return -1;
161         }
162
163         fd = open(dir_name->base_name, open_flags, 0);
164         if (fd == -1) {
165                 TALLOC_FREE(dir_name);
166                 return -1;
167         }
168
169         ret = fstatat_with_cap_dac_override(fd,
170                                             rel_name->base_name,
171                                             &smb_fname->st,
172                                             flag,
173                                             fake_dctime);
174
175         TALLOC_FREE(dir_name);
176         close(fd);
177
178         return ret;
179 }
180
181 int nfs4_acl_stat(struct vfs_handle_struct *handle,
182                   struct smb_filename *smb_fname)
183 {
184         int ret;
185
186         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
187         if (ret == -1 && errno == EACCES) {
188                 DEBUG(10, ("Trying stat with capability for %s\n",
189                            smb_fname->base_name));
190                 ret = stat_with_cap_dac_override(handle, smb_fname, 0);
191         }
192         return ret;
193 }
194
195 static int fstat_with_cap_dac_override(int fd, SMB_STRUCT_STAT *sbuf,
196                                        bool fake_dir_create_times)
197 {
198         int ret;
199
200         set_effective_capability(DAC_OVERRIDE_CAPABILITY);
201         ret = sys_fstat(fd, sbuf, fake_dir_create_times);
202         drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
203
204         return ret;
205 }
206
207 int nfs4_acl_fstat(struct vfs_handle_struct *handle,
208                    struct files_struct *fsp,
209                    SMB_STRUCT_STAT *sbuf)
210 {
211         int ret;
212
213         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
214         if (ret == -1 && errno == EACCES) {
215                 bool fake_dctime =
216                         lp_fake_directory_create_times(SNUM(handle->conn));
217
218                 DBG_DEBUG("fstat for %s failed with EACCES. Trying with "
219                           "CAP_DAC_OVERRIDE.\n", fsp->fsp_name->base_name);
220                 ret = fstat_with_cap_dac_override(fsp_get_pathref_fd(fsp),
221                                                   sbuf,
222                                                   fake_dctime);
223         }
224
225         return ret;
226 }
227
228 int nfs4_acl_lstat(struct vfs_handle_struct *handle,
229                    struct smb_filename *smb_fname)
230 {
231         int ret;
232
233         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
234         if (ret == -1 && errno == EACCES) {
235                 DEBUG(10, ("Trying lstat with capability for %s\n",
236                            smb_fname->base_name));
237                 ret = stat_with_cap_dac_override(handle, smb_fname,
238                                                  AT_SYMLINK_NOFOLLOW);
239         }
240         return ret;
241 }
242
243 int nfs4_acl_fstatat(struct vfs_handle_struct *handle,
244                      const struct files_struct *dirfsp,
245                      const struct smb_filename *smb_fname,
246                      SMB_STRUCT_STAT *sbuf,
247                      int flags)
248 {
249         int ret;
250
251         ret = SMB_VFS_NEXT_FSTATAT(handle, dirfsp, smb_fname, sbuf, flags);
252         if (ret == -1 && errno == EACCES) {
253                 bool fake_dctime =
254                         lp_fake_directory_create_times(SNUM(handle->conn));
255
256                 DBG_DEBUG("fstatat for %s failed with EACCES. Trying with "
257                           "CAP_DAC_OVERRIDE.\n", dirfsp->fsp_name->base_name);
258                 ret = fstatat_with_cap_dac_override(fsp_get_pathref_fd(dirfsp),
259                                                     smb_fname->base_name,
260                                                     sbuf,
261                                                     flags,
262                                                     fake_dctime);
263         }
264
265         return ret;
266 }
267
268 /************************************************
269  Split the ACE flag mapping between nfs4 and Windows
270  into two separate functions rather than trying to do
271  it inline. Allows us to carefully control what flags
272  are mapped to what in one place.
273 ************************************************/
274
275 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
276         uint32_t nfs4_ace_flags)
277 {
278         uint32_t win_ace_flags = 0;
279
280         /* The nfs4 flags <= 0xf map perfectly. */
281         win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
282                                       SEC_ACE_FLAG_CONTAINER_INHERIT|
283                                       SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
284                                       SEC_ACE_FLAG_INHERIT_ONLY);
285
286         /* flags greater than 0xf have diverged :-(. */
287         /* See the nfs4 ace flag definitions here:
288            http://www.ietf.org/rfc/rfc3530.txt.
289            And the Windows ace flag definitions here:
290            librpc/idl/security.idl. */
291         if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
292                 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
293         }
294
295         return win_ace_flags;
296 }
297
298 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
299 {
300         uint32_t nfs4_ace_flags = 0;
301
302         /* The windows flags <= 0xf map perfectly. */
303         nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
304                                       SMB_ACE4_DIRECTORY_INHERIT_ACE|
305                                       SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
306                                       SMB_ACE4_INHERIT_ONLY_ACE);
307
308         /* flags greater than 0xf have diverged :-(. */
309         /* See the nfs4 ace flag definitions here:
310            http://www.ietf.org/rfc/rfc3530.txt.
311            And the Windows ace flag definitions here:
312            librpc/idl/security.idl. */
313         if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
314                 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
315         }
316
317         return nfs4_ace_flags;
318 }
319
320 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
321 {
322         struct SMB4ACL_T *theacl;
323
324         theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
325         if (theacl==NULL)
326         {
327                 DEBUG(0, ("TALLOC_SIZE failed\n"));
328                 errno = ENOMEM;
329                 return NULL;
330         }
331         theacl->controlflags = SEC_DESC_SELF_RELATIVE;
332         /* theacl->first, last = NULL not needed */
333         return theacl;
334 }
335
336 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
337 {
338         struct SMB4ACE_T *ace;
339
340         ace = talloc_zero(acl, struct SMB4ACE_T);
341         if (ace==NULL)
342         {
343                 DBG_ERR("talloc_zero failed\n");
344                 errno = ENOMEM;
345                 return NULL;
346         }
347         ace->prop = *prop;
348
349         if (acl->first==NULL)
350         {
351                 acl->first = ace;
352                 acl->last = ace;
353         } else {
354                 acl->last->next = ace;
355                 acl->last = ace;
356         }
357         acl->naces++;
358
359         return ace;
360 }
361
362 SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
363 {
364         if (ace == NULL) {
365                 return NULL;
366         }
367
368         return &ace->prop;
369 }
370
371 struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
372 {
373         if (ace == NULL) {
374                 return NULL;
375         }
376
377         return ace->next;
378 }
379
380 struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
381 {
382         if (acl == NULL) {
383                 return NULL;
384         }
385
386         return acl->first;
387 }
388
389 uint32_t smb_get_naces(struct SMB4ACL_T *acl)
390 {
391         if (acl == NULL) {
392                 return 0;
393         }
394
395         return acl->naces;
396 }
397
398 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
399 {
400         if (acl == NULL) {
401                 return 0;
402         }
403
404         return acl->controlflags;
405 }
406
407 bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
408 {
409         if (acl == NULL) {
410                 return false;
411         }
412
413         acl->controlflags = controlflags;
414         return true;
415 }
416
417 bool nfs_ace_is_inherit(SMB_ACE4PROP_T *ace)
418 {
419         return ace->aceFlags & (SMB_ACE4_INHERIT_ONLY_ACE|
420                                 SMB_ACE4_FILE_INHERIT_ACE|
421                                 SMB_ACE4_DIRECTORY_INHERIT_ACE);
422 }
423
424 static int smbacl4_GetFileOwner(struct connection_struct *conn,
425                                 const struct smb_filename *smb_fname,
426                                 SMB_STRUCT_STAT *psbuf)
427 {
428         ZERO_STRUCTP(psbuf);
429
430         /* Get the stat struct for the owner info. */
431         if (vfs_stat_smb_basename(conn, smb_fname, psbuf) != 0)
432         {
433                 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
434                         strerror(errno)));
435                 return -1;
436         }
437
438         return 0;
439 }
440
441 static void check_for_duplicate_sec_ace(struct security_ace *nt_ace_list,
442                                         int *good_aces)
443 {
444         struct security_ace *last = NULL;
445         int i;
446
447         if (*good_aces < 2) {
448                 return;
449         }
450
451         last = &nt_ace_list[(*good_aces) - 1];
452
453         for (i = 0; i < (*good_aces) - 1; i++) {
454                 struct security_ace *cur = &nt_ace_list[i];
455
456                 if (cur->type == last->type &&
457                     cur->flags == last->flags &&
458                     cur->access_mask == last->access_mask &&
459                     dom_sid_equal(&cur->trustee, &last->trustee))
460                 {
461                         struct dom_sid_buf sid_buf;
462
463                         DBG_INFO("Removing duplicate entry for SID %s.\n",
464                                  dom_sid_str_buf(&last->trustee, &sid_buf));
465                         (*good_aces)--;
466                 }
467         }
468 }
469
470 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
471         const struct smbacl4_vfs_params *params,
472         struct SMB4ACL_T *acl, /* in */
473         struct dom_sid *psid_owner, /* in */
474         struct dom_sid *psid_group, /* in */
475         bool is_directory, /* in */
476         struct security_ace **ppnt_ace_list, /* out */
477         int *pgood_aces /* out */
478 )
479 {
480         struct SMB4ACE_T *aceint;
481         struct security_ace *nt_ace_list = NULL;
482         int good_aces = 0;
483
484         DEBUG(10, ("%s entered\n", __func__));
485
486         nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
487                                         2 * acl->naces);
488         if (nt_ace_list==NULL)
489         {
490                 DEBUG(10, ("talloc error with %d aces\n", acl->naces));
491                 errno = ENOMEM;
492                 return false;
493         }
494
495         for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
496                 uint32_t mask;
497                 struct dom_sid sid;
498                 struct dom_sid_buf buf;
499                 SMB_ACE4PROP_T  *ace = &aceint->prop;
500                 uint32_t win_ace_flags;
501
502                 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
503                            "mask: %x, who: %d\n",
504                            ace->aceType, ace->flags,
505                            ace->aceFlags, ace->aceMask, ace->who.id));
506
507                 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
508                         switch (ace->who.special_id) {
509                         case SMB_ACE4_WHO_OWNER:
510                                 sid_copy(&sid, psid_owner);
511                                 break;
512                         case SMB_ACE4_WHO_GROUP:
513                                 sid_copy(&sid, psid_group);
514                                 break;
515                         case SMB_ACE4_WHO_EVERYONE:
516                                 sid_copy(&sid, &global_sid_World);
517                                 break;
518                         default:
519                                 DEBUG(8, ("invalid special who id %d "
520                                         "ignored\n", ace->who.special_id));
521                                 continue;
522                         }
523                 } else {
524                         if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
525                                 gid_to_sid(&sid, ace->who.gid);
526                         } else {
527                                 uid_to_sid(&sid, ace->who.uid);
528                         }
529                 }
530                 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
531                            dom_sid_str_buf(&sid, &buf)));
532
533                 if (!is_directory && params->map_full_control) {
534                         /*
535                          * Do we have all access except DELETE_CHILD
536                          * (not caring about the delete bit).
537                          */
538                         uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
539                                                 SMB_ACE4_ALL_MASKS);
540                         if (test_mask == SMB_ACE4_ALL_MASKS) {
541                                 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
542                         }
543                 }
544
545                 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
546                         ace->aceFlags);
547                 if (!is_directory &&
548                     (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
549                                       SEC_ACE_FLAG_CONTAINER_INHERIT))) {
550                         /*
551                          * GPFS sets inherits dir_inherit and file_inherit flags
552                          * to files, too, which confuses windows, and seems to
553                          * be wrong anyways. ==> Map these bits away for files.
554                          */
555                         DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
556                         win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
557                                            SEC_ACE_FLAG_CONTAINER_INHERIT);
558                 }
559                 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
560                       ace->aceFlags, win_ace_flags));
561
562                 mask = ace->aceMask;
563
564                 /* Mapping of owner@ and group@ to creator owner and
565                    creator group. Keep old behavior in mode special. */
566                 if (params->mode != e_special &&
567                     ace->flags & SMB_ACE4_ID_SPECIAL &&
568                     (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
569                      ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
570                         DEBUG(10, ("Map special entry\n"));
571                         if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
572                                 uint32_t win_ace_flags_current;
573                                 DEBUG(10, ("Map current sid\n"));
574                                 win_ace_flags_current = win_ace_flags &
575                                         ~(SEC_ACE_FLAG_OBJECT_INHERIT |
576                                           SEC_ACE_FLAG_CONTAINER_INHERIT);
577                                 init_sec_ace(&nt_ace_list[good_aces++], &sid,
578                                              ace->aceType, mask,
579                                              win_ace_flags_current);
580                         }
581                         if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
582                             win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
583                                              SEC_ACE_FLAG_CONTAINER_INHERIT)) {
584                                 uint32_t win_ace_flags_creator;
585                                 DEBUG(10, ("Map creator owner\n"));
586                                 win_ace_flags_creator = win_ace_flags |
587                                         SMB_ACE4_INHERIT_ONLY_ACE;
588                                 init_sec_ace(&nt_ace_list[good_aces++],
589                                              &global_sid_Creator_Owner,
590                                              ace->aceType, mask,
591                                              win_ace_flags_creator);
592                         }
593                         if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
594                             win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
595                                              SEC_ACE_FLAG_CONTAINER_INHERIT)) {
596                                 uint32_t win_ace_flags_creator;
597                                 DEBUG(10, ("Map creator owner group\n"));
598                                 win_ace_flags_creator = win_ace_flags |
599                                         SMB_ACE4_INHERIT_ONLY_ACE;
600                                 init_sec_ace(&nt_ace_list[good_aces++],
601                                              &global_sid_Creator_Group,
602                                              ace->aceType, mask,
603                                              win_ace_flags_creator);
604                         }
605                 } else {
606                         DEBUG(10, ("Map normal sid\n"));
607                         init_sec_ace(&nt_ace_list[good_aces++], &sid,
608                                      ace->aceType, mask,
609                                      win_ace_flags);
610                 }
611
612                 check_for_duplicate_sec_ace(nt_ace_list, &good_aces);
613         }
614
615         nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
616                                      good_aces);
617
618         /* returns a NULL ace list when good_aces is zero. */
619         if (good_aces && nt_ace_list == NULL) {
620                 DEBUG(10, ("realloc error with %d aces\n", good_aces));
621                 errno = ENOMEM;
622                 return false;
623         }
624
625         *ppnt_ace_list = nt_ace_list;
626         *pgood_aces = good_aces;
627
628         return true;
629 }
630
631 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
632                                            const struct smbacl4_vfs_params *params,
633                                            uint32_t security_info,
634                                            TALLOC_CTX *mem_ctx,
635                                            struct security_descriptor **ppdesc,
636                                            struct SMB4ACL_T *theacl)
637 {
638         int good_aces = 0;
639         struct dom_sid sid_owner, sid_group;
640         size_t sd_size = 0;
641         struct security_ace *nt_ace_list = NULL;
642         struct security_acl *psa = NULL;
643         TALLOC_CTX *frame = talloc_stackframe();
644         bool ok;
645
646         if (theacl==NULL) {
647                 TALLOC_FREE(frame);
648                 return NT_STATUS_ACCESS_DENIED; /* special because we
649                                                  * need to think through
650                                                  * the null case.*/
651         }
652
653         uid_to_sid(&sid_owner, sbuf->st_ex_uid);
654         gid_to_sid(&sid_group, sbuf->st_ex_gid);
655
656         ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
657                               S_ISDIR(sbuf->st_ex_mode),
658                               &nt_ace_list, &good_aces);
659         if (!ok) {
660                 DEBUG(8,("smbacl4_nfs42win failed\n"));
661                 TALLOC_FREE(frame);
662                 return map_nt_error_from_unix(errno);
663         }
664
665         psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
666         if (psa == NULL) {
667                 DEBUG(2,("make_sec_acl failed\n"));
668                 TALLOC_FREE(frame);
669                 return NT_STATUS_NO_MEMORY;
670         }
671
672         DEBUG(10,("after make sec_acl\n"));
673         *ppdesc = make_sec_desc(
674                 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
675                 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
676                 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
677                 NULL, psa, &sd_size);
678         if (*ppdesc==NULL) {
679                 DEBUG(2,("make_sec_desc failed\n"));
680                 TALLOC_FREE(frame);
681                 return NT_STATUS_NO_MEMORY;
682         }
683
684         DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
685                    "sd_size %d\n",
686                    (int)ndr_size_security_descriptor(*ppdesc, 0)));
687
688         TALLOC_FREE(frame);
689         return NT_STATUS_OK;
690 }
691
692 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
693                               const struct smbacl4_vfs_params *pparams,
694                               uint32_t security_info,
695                               TALLOC_CTX *mem_ctx,
696                               struct security_descriptor **ppdesc,
697                               struct SMB4ACL_T *theacl)
698 {
699         struct smbacl4_vfs_params params;
700
701         DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
702
703         if (!VALID_STAT(fsp->fsp_name->st)) {
704                 NTSTATUS status;
705
706                 status = vfs_stat_fsp(fsp);
707                 if (!NT_STATUS_IS_OK(status)) {
708                         return status;
709                 }
710         }
711
712         if (pparams == NULL) {
713                 /* Special behaviours */
714                 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
715                         return NT_STATUS_NO_MEMORY;
716                 }
717                 pparams = &params;
718         }
719
720         return smb_get_nt_acl_nfs4_common(&fsp->fsp_name->st, pparams,
721                                           security_info,
722                                           mem_ctx, ppdesc, theacl);
723 }
724
725 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
726                              const struct smb_filename *smb_fname,
727                              const struct smbacl4_vfs_params *pparams,
728                              uint32_t security_info,
729                              TALLOC_CTX *mem_ctx,
730                              struct security_descriptor **ppdesc,
731                              struct SMB4ACL_T *theacl)
732 {
733         SMB_STRUCT_STAT sbuf;
734         struct smbacl4_vfs_params params;
735         const SMB_STRUCT_STAT *psbuf = NULL;
736
737         DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
738                 smb_fname->base_name));
739
740         if (VALID_STAT(smb_fname->st)) {
741                 psbuf = &smb_fname->st;
742         }
743
744         if (psbuf == NULL) {
745                 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
746                         return map_nt_error_from_unix(errno);
747                 }
748                 psbuf = &sbuf;
749         }
750
751         if (pparams == NULL) {
752                 /* Special behaviours */
753                 if (smbacl4_get_vfs_params(conn, &params)) {
754                         return NT_STATUS_NO_MEMORY;
755                 }
756                 pparams = &params;
757         }
758
759         return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
760                                           mem_ctx, ppdesc, theacl);
761 }
762
763 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
764 {
765         struct SMB4ACE_T *aceint;
766
767         DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
768
769         for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
770                 SMB_ACE4PROP_T *ace = &aceint->prop;
771
772                 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
773                               "mask=0x%x, id=%d\n",
774                               ace->aceType,
775                               ace->aceFlags, ace->flags,
776                               ace->aceMask,
777                               ace->who.id));
778         }
779 }
780
781 /*
782  * Find 2 NFS4 who-special ACE property (non-copy!!!)
783  * match nonzero if "special" and who is equal
784  * return ace if found matching; otherwise NULL
785  */
786 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
787         struct SMB4ACL_T *acl,
788         SMB_ACE4PROP_T *aceNew)
789 {
790         struct SMB4ACE_T *aceint;
791
792         for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
793                 SMB_ACE4PROP_T *ace = &aceint->prop;
794
795                 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
796                           "new type:0x%x flags:0x%x aceFlags:0x%x\n",
797                           ace->aceType, ace->flags, ace->aceFlags,
798                           aceNew->aceType, aceNew->flags,aceNew->aceFlags));
799
800                 if (ace->flags == aceNew->flags &&
801                         ace->aceType==aceNew->aceType &&
802                         ace->aceFlags==aceNew->aceFlags)
803                 {
804                         /* keep type safety; e.g. gid is an u.short */
805                         if (ace->flags & SMB_ACE4_ID_SPECIAL)
806                         {
807                                 if (ace->who.special_id ==
808                                     aceNew->who.special_id)
809                                         return ace;
810                         } else {
811                                 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
812                                 {
813                                         if (ace->who.gid==aceNew->who.gid)
814                                                 return ace;
815                                 } else {
816                                         if (ace->who.uid==aceNew->who.uid)
817                                                 return ace;
818                                 }
819                         }
820                 }
821         }
822
823         return NULL;
824 }
825
826 static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup,
827                                      struct SMB4ACL_T *theacl,
828                                      SMB_ACE4PROP_T *ace,
829                                      bool *paddNewACE)
830 {
831         int     result = 0;
832         SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
833         if (ace4found)
834         {
835                 switch(acedup)
836                 {
837                 case e_merge: /* "merge" flags */
838                         *paddNewACE = false;
839                         ace4found->aceFlags |= ace->aceFlags;
840                         ace4found->aceMask |= ace->aceMask;
841                         break;
842                 case e_ignore: /* leave out this record */
843                         *paddNewACE = false;
844                         break;
845                 case e_reject: /* do an error */
846                         DBG_INFO("ACL rejected by duplicate nt ace.\n");
847                         errno = EINVAL; /* SHOULD be set on any _real_ error */
848                         result = -1;
849                         break;
850                 default:
851                         break;
852                 }
853         }
854         return result;
855 }
856
857 static int nfs4_acl_add_ace(enum smbacl4_acedup_enum acedup,
858                             struct SMB4ACL_T *nfs4_acl,
859                             SMB_ACE4PROP_T *nfs4_ace)
860 {
861         bool add_ace = true;
862
863         if (acedup != e_dontcare) {
864                 int ret;
865
866                 ret = smbacl4_MergeIgnoreReject(acedup, nfs4_acl,
867                                                 nfs4_ace, &add_ace);
868                 if (ret == -1) {
869                         return -1;
870                 }
871         }
872
873         if (add_ace) {
874                 smb_add_ace4(nfs4_acl, nfs4_ace);
875         }
876
877         return 0;
878 }
879
880 static int nfs4_acl_add_sec_ace(bool is_directory,
881                                 const struct smbacl4_vfs_params *params,
882                                 uid_t ownerUID,
883                                 gid_t ownerGID,
884                                 const struct security_ace *ace_nt,
885                                 struct SMB4ACL_T *nfs4_acl)
886 {
887         struct dom_sid_buf buf;
888         SMB_ACE4PROP_T nfs4_ace = { 0 };
889         SMB_ACE4PROP_T nfs4_ace_2 = { 0 };
890         bool add_ace2 = false;
891         int ret;
892
893         DEBUG(10, ("got ace for %s\n",
894                    dom_sid_str_buf(&ace_nt->trustee, &buf)));
895
896         /* only ACCESS|DENY supported right now */
897         nfs4_ace.aceType = ace_nt->type;
898
899         nfs4_ace.aceFlags =
900                 map_windows_ace_flags_to_nfs4_ace_flags(ace_nt->flags);
901
902         /* remove inheritance flags on files */
903         if (!is_directory) {
904                 DEBUG(10, ("Removing inheritance flags from a file\n"));
905                 nfs4_ace.aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
906                                        SMB_ACE4_DIRECTORY_INHERIT_ACE|
907                                        SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
908                                        SMB_ACE4_INHERIT_ONLY_ACE);
909         }
910
911         nfs4_ace.aceMask = ace_nt->access_mask & (SEC_STD_ALL | SEC_FILE_ALL);
912
913         se_map_generic(&nfs4_ace.aceMask, &file_generic_mapping);
914
915         if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
916                 nfs4_ace.who.special_id = SMB_ACE4_WHO_EVERYONE;
917                 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
918         } else if (params->mode!=e_special &&
919                    dom_sid_equal(&ace_nt->trustee,
920                                  &global_sid_Creator_Owner)) {
921                 DEBUG(10, ("Map creator owner\n"));
922                 nfs4_ace.who.special_id = SMB_ACE4_WHO_OWNER;
923                 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
924                 /* A non inheriting creator owner entry has no effect. */
925                 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
926                 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
927                     && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
928                         return 0;
929                 }
930         } else if (params->mode!=e_special &&
931                    dom_sid_equal(&ace_nt->trustee,
932                                  &global_sid_Creator_Group)) {
933                 DEBUG(10, ("Map creator owner group\n"));
934                 nfs4_ace.who.special_id = SMB_ACE4_WHO_GROUP;
935                 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
936                 /* A non inheriting creator group entry has no effect. */
937                 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
938                 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
939                     && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
940                         return 0;
941                 }
942         } else {
943                 struct unixid unixid;
944                 bool ok;
945
946                 ok = sids_to_unixids(&ace_nt->trustee, 1, &unixid);
947                 if (!ok) {
948                         DBG_WARNING("Could not convert %s to uid or gid.\n",
949                                     dom_sid_str_buf(&ace_nt->trustee, &buf));
950                         return 0;
951                 }
952
953                 if (dom_sid_compare_domain(&ace_nt->trustee,
954                                            &global_sid_Unix_NFS) == 0) {
955                         return 0;
956                 }
957
958                 switch (unixid.type) {
959                 case ID_TYPE_BOTH:
960                         nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
961                         nfs4_ace.who.gid = unixid.id;
962
963                         if (ownerUID == unixid.id &&
964                             !nfs_ace_is_inherit(&nfs4_ace))
965                         {
966                                 /*
967                                  * IDMAP_TYPE_BOTH for owner. Add
968                                  * additional user entry, which can be
969                                  * mapped to special:owner to reflect
970                                  * the permissions in the modebits.
971                                  *
972                                  * This only applies to non-inheriting
973                                  * entries as only these are replaced
974                                  * with SPECIAL_OWNER in nfs4:mode=simple.
975                                  */
976                                 nfs4_ace_2 = (SMB_ACE4PROP_T) {
977                                         .who.uid = unixid.id,
978                                         .aceFlags = (nfs4_ace.aceFlags &
979                                                     ~SMB_ACE4_IDENTIFIER_GROUP),
980                                         .aceMask = nfs4_ace.aceMask,
981                                         .aceType = nfs4_ace.aceType,
982                                 };
983                                 add_ace2 = true;
984                         }
985                         break;
986                 case ID_TYPE_GID:
987                         nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
988                         nfs4_ace.who.gid = unixid.id;
989                         break;
990                 case ID_TYPE_UID:
991                         nfs4_ace.who.uid = unixid.id;
992                         break;
993                 case ID_TYPE_NOT_SPECIFIED:
994                 default:
995                         DBG_WARNING("Could not convert %s to uid or gid.\n",
996                                     dom_sid_str_buf(&ace_nt->trustee, &buf));
997                         return 0;
998                 }
999         }
1000
1001         ret = nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace);
1002         if (ret != 0) {
1003                 return -1;
1004         }
1005
1006         if (!add_ace2) {
1007                 return 0;
1008         }
1009
1010         return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace_2);
1011 }
1012
1013 static void smbacl4_substitute_special(struct SMB4ACL_T *acl,
1014                                        uid_t ownerUID,
1015                                        gid_t ownerGID)
1016 {
1017         struct SMB4ACE_T *aceint;
1018
1019         for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
1020                 SMB_ACE4PROP_T *ace = &aceint->prop;
1021
1022                 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
1023                           "mask: %x, who: %d\n",
1024                           ace->aceType, ace->flags, ace->aceFlags,
1025                           ace->aceMask, ace->who.id));
1026
1027                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
1028                     !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
1029                     ace->who.uid == ownerUID) {
1030                         ace->flags |= SMB_ACE4_ID_SPECIAL;
1031                         ace->who.special_id = SMB_ACE4_WHO_OWNER;
1032                         DEBUG(10,("replaced with special owner ace\n"));
1033                 }
1034
1035                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
1036                     ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
1037                     ace->who.uid == ownerGID) {
1038                         ace->flags |= SMB_ACE4_ID_SPECIAL;
1039                         ace->who.special_id = SMB_ACE4_WHO_GROUP;
1040                         DEBUG(10,("replaced with special group ace\n"));
1041                 }
1042         }
1043 }
1044
1045 static void smbacl4_substitute_simple(struct SMB4ACL_T *acl,
1046                                       uid_t ownerUID,
1047                                       gid_t ownerGID)
1048 {
1049         struct SMB4ACE_T *aceint;
1050
1051         for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
1052                 SMB_ACE4PROP_T *ace = &aceint->prop;
1053
1054                 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
1055                           "mask: %x, who: %d\n",
1056                           ace->aceType, ace->flags, ace->aceFlags,
1057                           ace->aceMask, ace->who.id));
1058
1059                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
1060                     !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
1061                     ace->who.uid == ownerUID &&
1062                     !nfs_ace_is_inherit(ace)) {
1063                         ace->flags |= SMB_ACE4_ID_SPECIAL;
1064                         ace->who.special_id = SMB_ACE4_WHO_OWNER;
1065                         DEBUG(10,("replaced with special owner ace\n"));
1066                 }
1067
1068                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
1069                     ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
1070                     ace->who.gid == ownerGID &&
1071                     !nfs_ace_is_inherit(ace)) {
1072                         ace->flags |= SMB_ACE4_ID_SPECIAL;
1073                         ace->who.special_id = SMB_ACE4_WHO_GROUP;
1074                         DEBUG(10,("replaced with special group ace\n"));
1075                 }
1076         }
1077 }
1078
1079 static struct SMB4ACL_T *smbacl4_win2nfs4(
1080         TALLOC_CTX *mem_ctx,
1081         bool is_directory,
1082         const struct security_acl *dacl,
1083         const struct smbacl4_vfs_params *pparams,
1084         uid_t ownerUID,
1085         gid_t ownerGID
1086 )
1087 {
1088         struct SMB4ACL_T *theacl;
1089         uint32_t i;
1090
1091         DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
1092
1093         theacl = smb_create_smb4acl(mem_ctx);
1094         if (theacl==NULL)
1095                 return NULL;
1096
1097         for(i=0; i<dacl->num_aces; i++) {
1098                 int ret;
1099
1100                 ret = nfs4_acl_add_sec_ace(is_directory, pparams,
1101                                            ownerUID, ownerGID,
1102                                            dacl->aces + i, theacl);
1103                 if (ret == -1) {
1104                         return NULL;
1105                 }
1106         }
1107
1108         if (pparams->mode==e_simple) {
1109                 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
1110         }
1111
1112         if (pparams->mode==e_special) {
1113                 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
1114         }
1115
1116         return theacl;
1117 }
1118
1119 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
1120         const struct smbacl4_vfs_params *pparams,
1121         uint32_t security_info_sent,
1122         const struct security_descriptor *psd,
1123         set_nfs4acl_native_fn_t set_nfs4_native)
1124 {
1125         struct smbacl4_vfs_params params;
1126         struct SMB4ACL_T *theacl = NULL;
1127         bool    result, is_directory;
1128
1129         bool set_acl_as_root = false;
1130         int saved_errno;
1131         NTSTATUS status;
1132         TALLOC_CTX *frame = talloc_stackframe();
1133
1134         DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
1135
1136         if ((security_info_sent & (SECINFO_DACL |
1137                 SECINFO_GROUP | SECINFO_OWNER)) == 0)
1138         {
1139                 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
1140                         security_info_sent));
1141                 TALLOC_FREE(frame);
1142                 return NT_STATUS_OK; /* won't show error - later to be
1143                                       * refined... */
1144         }
1145
1146         if (security_descriptor_with_ms_nfs(psd)) {
1147                 TALLOC_FREE(frame);
1148                 return NT_STATUS_OK;
1149         }
1150
1151         if (pparams == NULL) {
1152                 /* Special behaviours */
1153                 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
1154                         TALLOC_FREE(frame);
1155                         return NT_STATUS_NO_MEMORY;
1156                 }
1157                 pparams = &params;
1158         }
1159
1160         status = vfs_stat_fsp(fsp);
1161         if (!NT_STATUS_IS_OK(status)) {
1162                 TALLOC_FREE(frame);
1163                 return status;
1164         }
1165
1166         is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
1167
1168         if (pparams->do_chown) {
1169                 /*
1170                  * When the chown succeeds, the special entries in the
1171                  * file system ACL refer to the new owner. In order to
1172                  * apply the complete information from the DACL,
1173                  * setting the ACL then has to succeed. Track this
1174                  * case with set_acl_as_root and set the ACL as root
1175                  * accordingly.
1176                  */
1177                 status = chown_if_needed(fsp, security_info_sent, psd,
1178                                          &set_acl_as_root);
1179                 if (!NT_STATUS_IS_OK(status)) {
1180                         TALLOC_FREE(frame);
1181                         return status;
1182                 }
1183         }
1184
1185         if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1186                 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1187                            security_info_sent));
1188                 TALLOC_FREE(frame);
1189                 return NT_STATUS_OK;
1190         }
1191
1192         theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams,
1193                                   fsp->fsp_name->st.st_ex_uid,
1194                                   fsp->fsp_name->st.st_ex_gid);
1195         if (!theacl) {
1196                 TALLOC_FREE(frame);
1197                 return map_nt_error_from_unix(errno);
1198         }
1199
1200         smbacl4_set_controlflags(theacl, psd->type);
1201         smbacl4_dump_nfs4acl(10, theacl);
1202
1203         if (set_acl_as_root) {
1204                 become_root();
1205         }
1206         result = set_nfs4_native(handle, fsp, theacl);
1207         saved_errno = errno;
1208         if (set_acl_as_root) {
1209                 unbecome_root();
1210         }
1211
1212         TALLOC_FREE(frame);
1213
1214         if (result!=true) {
1215                 errno = saved_errno;
1216                 DEBUG(10, ("set_nfs4_native failed with %s\n",
1217                            strerror(errno)));
1218                 return map_nt_error_from_unix(errno);
1219         }
1220
1221         DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1222         return NT_STATUS_OK;
1223 }