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