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