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