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