vfs_gpfs: Move vfs_gpfs_stat to nfs4_acls.c and rename function
[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 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 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 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 /************************************************
208  Split the ACE flag mapping between nfs4 and Windows
209  into two separate functions rather than trying to do
210  it inline. Allows us to carefully control what flags
211  are mapped to what in one place.
212 ************************************************/
213
214 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
215         uint32_t nfs4_ace_flags)
216 {
217         uint32_t win_ace_flags = 0;
218
219         /* The nfs4 flags <= 0xf map perfectly. */
220         win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
221                                       SEC_ACE_FLAG_CONTAINER_INHERIT|
222                                       SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
223                                       SEC_ACE_FLAG_INHERIT_ONLY);
224
225         /* flags greater than 0xf have diverged :-(. */
226         /* See the nfs4 ace flag definitions here:
227            http://www.ietf.org/rfc/rfc3530.txt.
228            And the Windows ace flag definitions here:
229            librpc/idl/security.idl. */
230         if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
231                 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
232         }
233
234         return win_ace_flags;
235 }
236
237 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
238 {
239         uint32_t nfs4_ace_flags = 0;
240
241         /* The windows flags <= 0xf map perfectly. */
242         nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
243                                       SMB_ACE4_DIRECTORY_INHERIT_ACE|
244                                       SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
245                                       SMB_ACE4_INHERIT_ONLY_ACE);
246
247         /* flags greater than 0xf have diverged :-(. */
248         /* See the nfs4 ace flag definitions here:
249            http://www.ietf.org/rfc/rfc3530.txt.
250            And the Windows ace flag definitions here:
251            librpc/idl/security.idl. */
252         if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
253                 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
254         }
255
256         return nfs4_ace_flags;
257 }
258
259 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
260 {
261         struct SMB4ACL_T *theacl;
262
263         theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
264         if (theacl==NULL)
265         {
266                 DEBUG(0, ("TALLOC_SIZE failed\n"));
267                 errno = ENOMEM;
268                 return NULL;
269         }
270         theacl->controlflags = SEC_DESC_SELF_RELATIVE;
271         /* theacl->first, last = NULL not needed */
272         return theacl;
273 }
274
275 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
276 {
277         struct SMB4ACE_T *ace;
278
279         ace = talloc_zero(acl, struct SMB4ACE_T);
280         if (ace==NULL)
281         {
282                 DBG_ERR("talloc_zero failed\n");
283                 errno = ENOMEM;
284                 return NULL;
285         }
286         ace->prop = *prop;
287
288         if (acl->first==NULL)
289         {
290                 acl->first = ace;
291                 acl->last = ace;
292         } else {
293                 acl->last->next = ace;
294                 acl->last = ace;
295         }
296         acl->naces++;
297
298         return ace;
299 }
300
301 SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
302 {
303         if (ace == NULL) {
304                 return NULL;
305         }
306
307         return &ace->prop;
308 }
309
310 struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
311 {
312         if (ace == NULL) {
313                 return NULL;
314         }
315
316         return ace->next;
317 }
318
319 struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
320 {
321         if (acl == NULL) {
322                 return NULL;
323         }
324
325         return acl->first;
326 }
327
328 uint32_t smb_get_naces(struct SMB4ACL_T *acl)
329 {
330         if (acl == NULL) {
331                 return 0;
332         }
333
334         return acl->naces;
335 }
336
337 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
338 {
339         if (acl == NULL) {
340                 return 0;
341         }
342
343         return acl->controlflags;
344 }
345
346 bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
347 {
348         if (acl == NULL) {
349                 return false;
350         }
351
352         acl->controlflags = controlflags;
353         return true;
354 }
355
356 bool nfs_ace_is_inherit(SMB_ACE4PROP_T *ace)
357 {
358         return ace->aceFlags & (SMB_ACE4_INHERIT_ONLY_ACE|
359                                 SMB_ACE4_FILE_INHERIT_ACE|
360                                 SMB_ACE4_DIRECTORY_INHERIT_ACE);
361 }
362
363 static int smbacl4_GetFileOwner(struct connection_struct *conn,
364                                 const struct smb_filename *smb_fname,
365                                 SMB_STRUCT_STAT *psbuf)
366 {
367         ZERO_STRUCTP(psbuf);
368
369         /* Get the stat struct for the owner info. */
370         if (vfs_stat_smb_basename(conn, smb_fname, psbuf) != 0)
371         {
372                 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
373                         strerror(errno)));
374                 return -1;
375         }
376
377         return 0;
378 }
379
380 static void check_for_duplicate_sec_ace(struct security_ace *nt_ace_list,
381                                         int *good_aces)
382 {
383         struct security_ace *last = NULL;
384         int i;
385
386         if (*good_aces < 2) {
387                 return;
388         }
389
390         last = &nt_ace_list[(*good_aces) - 1];
391
392         for (i = 0; i < (*good_aces) - 1; i++) {
393                 struct security_ace *cur = &nt_ace_list[i];
394
395                 if (cur->type == last->type &&
396                     cur->flags == last->flags &&
397                     cur->access_mask == last->access_mask &&
398                     dom_sid_equal(&cur->trustee, &last->trustee))
399                 {
400                         struct dom_sid_buf sid_buf;
401
402                         DBG_INFO("Removing duplicate entry for SID %s.\n",
403                                  dom_sid_str_buf(&last->trustee, &sid_buf));
404                         (*good_aces)--;
405                 }
406         }
407 }
408
409 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
410         const struct smbacl4_vfs_params *params,
411         struct SMB4ACL_T *acl, /* in */
412         struct dom_sid *psid_owner, /* in */
413         struct dom_sid *psid_group, /* in */
414         bool is_directory, /* in */
415         struct security_ace **ppnt_ace_list, /* out */
416         int *pgood_aces /* out */
417 )
418 {
419         struct SMB4ACE_T *aceint;
420         struct security_ace *nt_ace_list = NULL;
421         int good_aces = 0;
422
423         DEBUG(10, ("%s entered\n", __func__));
424
425         nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
426                                         2 * acl->naces);
427         if (nt_ace_list==NULL)
428         {
429                 DEBUG(10, ("talloc error with %d aces", acl->naces));
430                 errno = ENOMEM;
431                 return false;
432         }
433
434         for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
435                 uint32_t mask;
436                 struct dom_sid sid;
437                 struct dom_sid_buf buf;
438                 SMB_ACE4PROP_T  *ace = &aceint->prop;
439                 uint32_t win_ace_flags;
440
441                 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
442                            "mask: %x, who: %d\n",
443                            ace->aceType, ace->flags,
444                            ace->aceFlags, ace->aceMask, ace->who.id));
445
446                 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
447                         switch (ace->who.special_id) {
448                         case SMB_ACE4_WHO_OWNER:
449                                 sid_copy(&sid, psid_owner);
450                                 break;
451                         case SMB_ACE4_WHO_GROUP:
452                                 sid_copy(&sid, psid_group);
453                                 break;
454                         case SMB_ACE4_WHO_EVERYONE:
455                                 sid_copy(&sid, &global_sid_World);
456                                 break;
457                         default:
458                                 DEBUG(8, ("invalid special who id %d "
459                                         "ignored\n", ace->who.special_id));
460                                 continue;
461                         }
462                 } else {
463                         if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
464                                 gid_to_sid(&sid, ace->who.gid);
465                         } else {
466                                 uid_to_sid(&sid, ace->who.uid);
467                         }
468                 }
469                 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
470                            dom_sid_str_buf(&sid, &buf)));
471
472                 if (!is_directory && params->map_full_control) {
473                         /*
474                          * Do we have all access except DELETE_CHILD
475                          * (not caring about the delete bit).
476                          */
477                         uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
478                                                 SMB_ACE4_ALL_MASKS);
479                         if (test_mask == SMB_ACE4_ALL_MASKS) {
480                                 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
481                         }
482                 }
483
484                 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
485                         ace->aceFlags);
486                 if (!is_directory &&
487                     (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
488                                       SEC_ACE_FLAG_CONTAINER_INHERIT))) {
489                         /*
490                          * GPFS sets inherits dir_inhert and file_inherit flags
491                          * to files, too, which confuses windows, and seems to
492                          * be wrong anyways. ==> Map these bits away for files.
493                          */
494                         DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
495                         win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
496                                            SEC_ACE_FLAG_CONTAINER_INHERIT);
497                 }
498                 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
499                       ace->aceFlags, win_ace_flags));
500
501                 mask = ace->aceMask;
502
503                 /* Mapping of owner@ and group@ to creator owner and
504                    creator group. Keep old behavior in mode special. */
505                 if (params->mode != e_special &&
506                     ace->flags & SMB_ACE4_ID_SPECIAL &&
507                     (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
508                      ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
509                         DEBUG(10, ("Map special entry\n"));
510                         if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
511                                 uint32_t win_ace_flags_current;
512                                 DEBUG(10, ("Map current sid\n"));
513                                 win_ace_flags_current = win_ace_flags &
514                                         ~(SEC_ACE_FLAG_OBJECT_INHERIT |
515                                           SEC_ACE_FLAG_CONTAINER_INHERIT);
516                                 init_sec_ace(&nt_ace_list[good_aces++], &sid,
517                                              ace->aceType, mask,
518                                              win_ace_flags_current);
519                         }
520                         if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
521                             win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
522                                              SEC_ACE_FLAG_CONTAINER_INHERIT)) {
523                                 uint32_t win_ace_flags_creator;
524                                 DEBUG(10, ("Map creator owner\n"));
525                                 win_ace_flags_creator = win_ace_flags |
526                                         SMB_ACE4_INHERIT_ONLY_ACE;
527                                 init_sec_ace(&nt_ace_list[good_aces++],
528                                              &global_sid_Creator_Owner,
529                                              ace->aceType, mask,
530                                              win_ace_flags_creator);
531                         }
532                         if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
533                             win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
534                                              SEC_ACE_FLAG_CONTAINER_INHERIT)) {
535                                 uint32_t win_ace_flags_creator;
536                                 DEBUG(10, ("Map creator owner group\n"));
537                                 win_ace_flags_creator = win_ace_flags |
538                                         SMB_ACE4_INHERIT_ONLY_ACE;
539                                 init_sec_ace(&nt_ace_list[good_aces++],
540                                              &global_sid_Creator_Group,
541                                              ace->aceType, mask,
542                                              win_ace_flags_creator);
543                         }
544                 } else {
545                         DEBUG(10, ("Map normal sid\n"));
546                         init_sec_ace(&nt_ace_list[good_aces++], &sid,
547                                      ace->aceType, mask,
548                                      win_ace_flags);
549                 }
550
551                 check_for_duplicate_sec_ace(nt_ace_list, &good_aces);
552         }
553
554         nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
555                                      good_aces);
556
557         /* returns a NULL ace list when good_aces is zero. */
558         if (good_aces && nt_ace_list == NULL) {
559                 DEBUG(10, ("realloc error with %d aces", good_aces));
560                 errno = ENOMEM;
561                 return false;
562         }
563
564         *ppnt_ace_list = nt_ace_list;
565         *pgood_aces = good_aces;
566
567         return true;
568 }
569
570 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
571                                            const struct smbacl4_vfs_params *params,
572                                            uint32_t security_info,
573                                            TALLOC_CTX *mem_ctx,
574                                            struct security_descriptor **ppdesc,
575                                            struct SMB4ACL_T *theacl)
576 {
577         int good_aces = 0;
578         struct dom_sid sid_owner, sid_group;
579         size_t sd_size = 0;
580         struct security_ace *nt_ace_list = NULL;
581         struct security_acl *psa = NULL;
582         TALLOC_CTX *frame = talloc_stackframe();
583         bool ok;
584
585         if (theacl==NULL) {
586                 TALLOC_FREE(frame);
587                 return NT_STATUS_ACCESS_DENIED; /* special because we
588                                                  * need to think through
589                                                  * the null case.*/
590         }
591
592         uid_to_sid(&sid_owner, sbuf->st_ex_uid);
593         gid_to_sid(&sid_group, sbuf->st_ex_gid);
594
595         ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
596                               S_ISDIR(sbuf->st_ex_mode),
597                               &nt_ace_list, &good_aces);
598         if (!ok) {
599                 DEBUG(8,("smbacl4_nfs42win failed\n"));
600                 TALLOC_FREE(frame);
601                 return map_nt_error_from_unix(errno);
602         }
603
604         psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
605         if (psa == NULL) {
606                 DEBUG(2,("make_sec_acl failed\n"));
607                 TALLOC_FREE(frame);
608                 return NT_STATUS_NO_MEMORY;
609         }
610
611         DEBUG(10,("after make sec_acl\n"));
612         *ppdesc = make_sec_desc(
613                 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
614                 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
615                 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
616                 NULL, psa, &sd_size);
617         if (*ppdesc==NULL) {
618                 DEBUG(2,("make_sec_desc failed\n"));
619                 TALLOC_FREE(frame);
620                 return NT_STATUS_NO_MEMORY;
621         }
622
623         DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
624                    "sd_size %d\n",
625                    (int)ndr_size_security_descriptor(*ppdesc, 0)));
626
627         TALLOC_FREE(frame);
628         return NT_STATUS_OK;
629 }
630
631 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
632                               const struct smbacl4_vfs_params *pparams,
633                               uint32_t security_info,
634                               TALLOC_CTX *mem_ctx,
635                               struct security_descriptor **ppdesc,
636                               struct SMB4ACL_T *theacl)
637 {
638         struct smbacl4_vfs_params params;
639
640         DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
641
642         if (!VALID_STAT(fsp->fsp_name->st)) {
643                 NTSTATUS status;
644
645                 status = vfs_stat_fsp(fsp);
646                 if (!NT_STATUS_IS_OK(status)) {
647                         return status;
648                 }
649         }
650
651         if (pparams == NULL) {
652                 /* Special behaviours */
653                 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
654                         return NT_STATUS_NO_MEMORY;
655                 }
656                 pparams = &params;
657         }
658
659         return smb_get_nt_acl_nfs4_common(&fsp->fsp_name->st, pparams,
660                                           security_info,
661                                           mem_ctx, ppdesc, theacl);
662 }
663
664 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
665                              const struct smb_filename *smb_fname,
666                              const struct smbacl4_vfs_params *pparams,
667                              uint32_t security_info,
668                              TALLOC_CTX *mem_ctx,
669                              struct security_descriptor **ppdesc,
670                              struct SMB4ACL_T *theacl)
671 {
672         SMB_STRUCT_STAT sbuf;
673         struct smbacl4_vfs_params params;
674         const SMB_STRUCT_STAT *psbuf = NULL;
675
676         DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
677                 smb_fname->base_name));
678
679         if (VALID_STAT(smb_fname->st)) {
680                 psbuf = &smb_fname->st;
681         }
682
683         if (psbuf == NULL) {
684                 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
685                         return map_nt_error_from_unix(errno);
686                 }
687                 psbuf = &sbuf;
688         }
689
690         if (pparams == NULL) {
691                 /* Special behaviours */
692                 if (smbacl4_get_vfs_params(conn, &params)) {
693                         return NT_STATUS_NO_MEMORY;
694                 }
695                 pparams = &params;
696         }
697
698         return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
699                                           mem_ctx, ppdesc, theacl);
700 }
701
702 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
703 {
704         struct SMB4ACE_T *aceint;
705
706         DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
707
708         for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
709                 SMB_ACE4PROP_T *ace = &aceint->prop;
710
711                 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
712                               "mask=0x%x, id=%d\n",
713                               ace->aceType,
714                               ace->aceFlags, ace->flags,
715                               ace->aceMask,
716                               ace->who.id));
717         }
718 }
719
720 /*
721  * Find 2 NFS4 who-special ACE property (non-copy!!!)
722  * match nonzero if "special" and who is equal
723  * return ace if found matching; otherwise NULL
724  */
725 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
726         struct SMB4ACL_T *acl,
727         SMB_ACE4PROP_T *aceNew)
728 {
729         struct SMB4ACE_T *aceint;
730
731         for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
732                 SMB_ACE4PROP_T *ace = &aceint->prop;
733
734                 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
735                           "new type:0x%x flags:0x%x aceFlags:0x%x\n",
736                           ace->aceType, ace->flags, ace->aceFlags,
737                           aceNew->aceType, aceNew->flags,aceNew->aceFlags));
738
739                 if (ace->flags == aceNew->flags &&
740                         ace->aceType==aceNew->aceType &&
741                         ace->aceFlags==aceNew->aceFlags)
742                 {
743                         /* keep type safety; e.g. gid is an u.short */
744                         if (ace->flags & SMB_ACE4_ID_SPECIAL)
745                         {
746                                 if (ace->who.special_id ==
747                                     aceNew->who.special_id)
748                                         return ace;
749                         } else {
750                                 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
751                                 {
752                                         if (ace->who.gid==aceNew->who.gid)
753                                                 return ace;
754                                 } else {
755                                         if (ace->who.uid==aceNew->who.uid)
756                                                 return ace;
757                                 }
758                         }
759                 }
760         }
761
762         return NULL;
763 }
764
765 static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup,
766                                      struct SMB4ACL_T *theacl,
767                                      SMB_ACE4PROP_T *ace,
768                                      bool *paddNewACE)
769 {
770         int     result = 0;
771         SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
772         if (ace4found)
773         {
774                 switch(acedup)
775                 {
776                 case e_merge: /* "merge" flags */
777                         *paddNewACE = false;
778                         ace4found->aceFlags |= ace->aceFlags;
779                         ace4found->aceMask |= ace->aceMask;
780                         break;
781                 case e_ignore: /* leave out this record */
782                         *paddNewACE = false;
783                         break;
784                 case e_reject: /* do an error */
785                         DBG_INFO("ACL rejected by duplicate nt ace.\n");
786                         errno = EINVAL; /* SHOULD be set on any _real_ error */
787                         result = -1;
788                         break;
789                 default:
790                         break;
791                 }
792         }
793         return result;
794 }
795
796 static int nfs4_acl_add_ace(enum smbacl4_acedup_enum acedup,
797                             struct SMB4ACL_T *nfs4_acl,
798                             SMB_ACE4PROP_T *nfs4_ace)
799 {
800         bool add_ace = true;
801
802         if (acedup != e_dontcare) {
803                 int ret;
804
805                 ret = smbacl4_MergeIgnoreReject(acedup, nfs4_acl,
806                                                 nfs4_ace, &add_ace);
807                 if (ret == -1) {
808                         return -1;
809                 }
810         }
811
812         if (add_ace) {
813                 smb_add_ace4(nfs4_acl, nfs4_ace);
814         }
815
816         return 0;
817 }
818
819 static int nfs4_acl_add_sec_ace(bool is_directory,
820                                 const struct smbacl4_vfs_params *params,
821                                 uid_t ownerUID,
822                                 gid_t ownerGID,
823                                 const struct security_ace *ace_nt,
824                                 struct SMB4ACL_T *nfs4_acl)
825 {
826         struct dom_sid_buf buf;
827         SMB_ACE4PROP_T nfs4_ace = { 0 };
828         SMB_ACE4PROP_T nfs4_ace_2 = { 0 };
829         bool add_ace2 = false;
830         int ret;
831
832         DEBUG(10, ("got ace for %s\n",
833                    dom_sid_str_buf(&ace_nt->trustee, &buf)));
834
835         /* only ACCESS|DENY supported right now */
836         nfs4_ace.aceType = ace_nt->type;
837
838         nfs4_ace.aceFlags =
839                 map_windows_ace_flags_to_nfs4_ace_flags(ace_nt->flags);
840
841         /* remove inheritance flags on files */
842         if (!is_directory) {
843                 DEBUG(10, ("Removing inheritance flags from a file\n"));
844                 nfs4_ace.aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
845                                        SMB_ACE4_DIRECTORY_INHERIT_ACE|
846                                        SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
847                                        SMB_ACE4_INHERIT_ONLY_ACE);
848         }
849
850         nfs4_ace.aceMask = ace_nt->access_mask & (SEC_STD_ALL | SEC_FILE_ALL);
851
852         se_map_generic(&nfs4_ace.aceMask, &file_generic_mapping);
853
854         if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
855                 nfs4_ace.who.special_id = SMB_ACE4_WHO_EVERYONE;
856                 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
857         } else if (params->mode!=e_special &&
858                    dom_sid_equal(&ace_nt->trustee,
859                                  &global_sid_Creator_Owner)) {
860                 DEBUG(10, ("Map creator owner\n"));
861                 nfs4_ace.who.special_id = SMB_ACE4_WHO_OWNER;
862                 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
863                 /* A non inheriting creator owner entry has no effect. */
864                 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
865                 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
866                     && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
867                         return 0;
868                 }
869         } else if (params->mode!=e_special &&
870                    dom_sid_equal(&ace_nt->trustee,
871                                  &global_sid_Creator_Group)) {
872                 DEBUG(10, ("Map creator owner group\n"));
873                 nfs4_ace.who.special_id = SMB_ACE4_WHO_GROUP;
874                 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
875                 /* A non inheriting creator group entry has no effect. */
876                 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
877                 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
878                     && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
879                         return 0;
880                 }
881         } else {
882                 struct unixid unixid;
883                 bool ok;
884
885                 ok = sids_to_unixids(&ace_nt->trustee, 1, &unixid);
886                 if (!ok) {
887                         DBG_WARNING("Could not convert %s to uid or gid.\n",
888                                     dom_sid_str_buf(&ace_nt->trustee, &buf));
889                         return 0;
890                 }
891
892                 if (dom_sid_compare_domain(&ace_nt->trustee,
893                                            &global_sid_Unix_NFS) == 0) {
894                         return 0;
895                 }
896
897                 switch (unixid.type) {
898                 case ID_TYPE_BOTH:
899                         nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
900                         nfs4_ace.who.gid = unixid.id;
901
902                         if (ownerUID == unixid.id &&
903                             !nfs_ace_is_inherit(&nfs4_ace))
904                         {
905                                 /*
906                                  * IDMAP_TYPE_BOTH for owner. Add
907                                  * additional user entry, which can be
908                                  * mapped to special:owner to reflect
909                                  * the permissions in the modebits.
910                                  *
911                                  * This only applies to non-inheriting
912                                  * entries as only these are replaced
913                                  * with SPECIAL_OWNER in nfs4:mode=simple.
914                                  */
915                                 nfs4_ace_2 = (SMB_ACE4PROP_T) {
916                                         .who.uid = unixid.id,
917                                         .aceFlags = (nfs4_ace.aceFlags &
918                                                     ~SMB_ACE4_IDENTIFIER_GROUP),
919                                         .aceMask = nfs4_ace.aceMask,
920                                         .aceType = nfs4_ace.aceType,
921                                 };
922                                 add_ace2 = true;
923                         }
924                         break;
925                 case ID_TYPE_GID:
926                         nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
927                         nfs4_ace.who.gid = unixid.id;
928                         break;
929                 case ID_TYPE_UID:
930                         nfs4_ace.who.uid = unixid.id;
931                         break;
932                 case ID_TYPE_NOT_SPECIFIED:
933                 default:
934                         DBG_WARNING("Could not convert %s to uid or gid.\n",
935                                     dom_sid_str_buf(&ace_nt->trustee, &buf));
936                         return 0;
937                 }
938         }
939
940         ret = nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace);
941         if (ret != 0) {
942                 return -1;
943         }
944
945         if (!add_ace2) {
946                 return 0;
947         }
948
949         return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace_2);
950 }
951
952 static void smbacl4_substitute_special(struct SMB4ACL_T *acl,
953                                        uid_t ownerUID,
954                                        gid_t ownerGID)
955 {
956         struct SMB4ACE_T *aceint;
957
958         for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
959                 SMB_ACE4PROP_T *ace = &aceint->prop;
960
961                 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
962                           "mask: %x, who: %d\n",
963                           ace->aceType, ace->flags, ace->aceFlags,
964                           ace->aceMask, ace->who.id));
965
966                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
967                     !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
968                     ace->who.uid == ownerUID) {
969                         ace->flags |= SMB_ACE4_ID_SPECIAL;
970                         ace->who.special_id = SMB_ACE4_WHO_OWNER;
971                         DEBUG(10,("replaced with special owner ace\n"));
972                 }
973
974                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
975                     ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
976                     ace->who.uid == ownerGID) {
977                         ace->flags |= SMB_ACE4_ID_SPECIAL;
978                         ace->who.special_id = SMB_ACE4_WHO_GROUP;
979                         DEBUG(10,("replaced with special group ace\n"));
980                 }
981         }
982 }
983
984 static void smbacl4_substitute_simple(struct SMB4ACL_T *acl,
985                                       uid_t ownerUID,
986                                       gid_t ownerGID)
987 {
988         struct SMB4ACE_T *aceint;
989
990         for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
991                 SMB_ACE4PROP_T *ace = &aceint->prop;
992
993                 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
994                           "mask: %x, who: %d\n",
995                           ace->aceType, ace->flags, ace->aceFlags,
996                           ace->aceMask, ace->who.id));
997
998                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
999                     !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
1000                     ace->who.uid == ownerUID &&
1001                     !nfs_ace_is_inherit(ace)) {
1002                         ace->flags |= SMB_ACE4_ID_SPECIAL;
1003                         ace->who.special_id = SMB_ACE4_WHO_OWNER;
1004                         DEBUG(10,("replaced with special owner ace\n"));
1005                 }
1006
1007                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
1008                     ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
1009                     ace->who.gid == ownerGID &&
1010                     !nfs_ace_is_inherit(ace)) {
1011                         ace->flags |= SMB_ACE4_ID_SPECIAL;
1012                         ace->who.special_id = SMB_ACE4_WHO_GROUP;
1013                         DEBUG(10,("replaced with special group ace\n"));
1014                 }
1015         }
1016 }
1017
1018 static struct SMB4ACL_T *smbacl4_win2nfs4(
1019         TALLOC_CTX *mem_ctx,
1020         bool is_directory,
1021         const struct security_acl *dacl,
1022         const struct smbacl4_vfs_params *pparams,
1023         uid_t ownerUID,
1024         gid_t ownerGID
1025 )
1026 {
1027         struct SMB4ACL_T *theacl;
1028         uint32_t i;
1029
1030         DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
1031
1032         theacl = smb_create_smb4acl(mem_ctx);
1033         if (theacl==NULL)
1034                 return NULL;
1035
1036         for(i=0; i<dacl->num_aces; i++) {
1037                 int ret;
1038
1039                 ret = nfs4_acl_add_sec_ace(is_directory, pparams,
1040                                            ownerUID, ownerGID,
1041                                            dacl->aces + i, theacl);
1042                 if (ret == -1) {
1043                         return NULL;
1044                 }
1045         }
1046
1047         if (pparams->mode==e_simple) {
1048                 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
1049         }
1050
1051         if (pparams->mode==e_special) {
1052                 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
1053         }
1054
1055         return theacl;
1056 }
1057
1058 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
1059         const struct smbacl4_vfs_params *pparams,
1060         uint32_t security_info_sent,
1061         const struct security_descriptor *psd,
1062         set_nfs4acl_native_fn_t set_nfs4_native)
1063 {
1064         struct smbacl4_vfs_params params;
1065         struct SMB4ACL_T *theacl = NULL;
1066         bool    result, is_directory;
1067
1068         bool set_acl_as_root = false;
1069         int saved_errno;
1070         NTSTATUS status;
1071         TALLOC_CTX *frame = talloc_stackframe();
1072
1073         DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
1074
1075         if ((security_info_sent & (SECINFO_DACL |
1076                 SECINFO_GROUP | SECINFO_OWNER)) == 0)
1077         {
1078                 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
1079                         security_info_sent));
1080                 TALLOC_FREE(frame);
1081                 return NT_STATUS_OK; /* won't show error - later to be
1082                                       * refined... */
1083         }
1084
1085         if (security_descriptor_with_ms_nfs(psd)) {
1086                 TALLOC_FREE(frame);
1087                 return NT_STATUS_OK;
1088         }
1089
1090         if (pparams == NULL) {
1091                 /* Special behaviours */
1092                 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
1093                         TALLOC_FREE(frame);
1094                         return NT_STATUS_NO_MEMORY;
1095                 }
1096                 pparams = &params;
1097         }
1098
1099         status = vfs_stat_fsp(fsp);
1100         if (!NT_STATUS_IS_OK(status)) {
1101                 TALLOC_FREE(frame);
1102                 return status;
1103         }
1104
1105         is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
1106
1107         if (pparams->do_chown) {
1108                 /*
1109                  * When the chown succeeds, the special entries in the
1110                  * file system ACL refer to the new owner. In order to
1111                  * apply the complete information from the DACL,
1112                  * setting the ACL then has to succeed. Track this
1113                  * case with set_acl_as_root and set the ACL as root
1114                  * accordingly.
1115                  */
1116                 status = chown_if_needed(fsp, security_info_sent, psd,
1117                                          &set_acl_as_root);
1118                 if (!NT_STATUS_IS_OK(status)) {
1119                         TALLOC_FREE(frame);
1120                         return status;
1121                 }
1122         }
1123
1124         if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1125                 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1126                            security_info_sent));
1127                 TALLOC_FREE(frame);
1128                 return NT_STATUS_OK;
1129         }
1130
1131         theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams,
1132                                   fsp->fsp_name->st.st_ex_uid,
1133                                   fsp->fsp_name->st.st_ex_gid);
1134         if (!theacl) {
1135                 TALLOC_FREE(frame);
1136                 return map_nt_error_from_unix(errno);
1137         }
1138
1139         smbacl4_set_controlflags(theacl, psd->type);
1140         smbacl4_dump_nfs4acl(10, theacl);
1141
1142         if (set_acl_as_root) {
1143                 become_root();
1144         }
1145         result = set_nfs4_native(handle, fsp, theacl);
1146         saved_errno = errno;
1147         if (set_acl_as_root) {
1148                 unbecome_root();
1149         }
1150
1151         TALLOC_FREE(frame);
1152
1153         if (result!=true) {
1154                 errno = saved_errno;
1155                 DEBUG(10, ("set_nfs4_native failed with %s\n",
1156                            strerror(errno)));
1157                 return map_nt_error_from_unix(errno);
1158         }
1159
1160         DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1161         return NT_STATUS_OK;
1162 }