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