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