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