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