nfs4_acls: Remove redundant logging from 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 (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
750                 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
751                 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
752         } else if (params->mode!=e_special &&
753                    dom_sid_equal(&ace_nt->trustee,
754                                  &global_sid_Creator_Owner)) {
755                 DEBUG(10, ("Map creator owner\n"));
756                 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
757                 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
758                 /* A non inheriting creator owner entry has no effect. */
759                 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
760                 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
761                     && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
762                         return 0;
763                 }
764         } else if (params->mode!=e_special &&
765                    dom_sid_equal(&ace_nt->trustee,
766                                  &global_sid_Creator_Group)) {
767                 DEBUG(10, ("Map creator owner group\n"));
768                 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
769                 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
770                 /* A non inheriting creator group entry has no effect. */
771                 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
772                 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
773                     && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
774                         return 0;
775                 }
776         } else {
777                 struct unixid unixid;
778                 bool ok;
779
780                 ok = sids_to_unixids(&ace_nt->trustee, 1, &unixid);
781                 if (!ok) {
782                         DBG_WARNING("Could not convert %s to uid or gid.\n",
783                                     dom_sid_str_buf(&ace_nt->trustee, &buf));
784                         return 0;
785                 }
786
787                 if (dom_sid_compare_domain(&ace_nt->trustee,
788                                            &global_sid_Unix_NFS) == 0) {
789                         return 0;
790                 }
791
792                 switch (unixid.type) {
793                 case ID_TYPE_BOTH:
794                         ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
795                         ace_v4->who.gid = unixid.id;
796                         break;
797                 case ID_TYPE_GID:
798                         ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
799                         ace_v4->who.gid = unixid.id;
800                         break;
801                 case ID_TYPE_UID:
802                         ace_v4->who.uid = unixid.id;
803                         break;
804                 case ID_TYPE_NOT_SPECIFIED:
805                 default:
806                         DBG_WARNING("Could not convert %s to uid or gid.\n",
807                                     dom_sid_str_buf(&ace_nt->trustee, &buf));
808                         return 0;
809                 }
810         }
811
812         return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace);
813 }
814
815 static void smbacl4_substitute_special(struct SMB4ACL_T *acl,
816                                        uid_t ownerUID,
817                                        gid_t ownerGID)
818 {
819         struct SMB4ACE_T *aceint;
820
821         for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
822                 SMB_ACE4PROP_T *ace = &aceint->prop;
823
824                 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
825                           "mask: %x, who: %d\n",
826                           ace->aceType, ace->flags, ace->aceFlags,
827                           ace->aceMask, ace->who.id));
828
829                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
830                     !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
831                     ace->who.uid == ownerUID) {
832                         ace->flags |= SMB_ACE4_ID_SPECIAL;
833                         ace->who.special_id = SMB_ACE4_WHO_OWNER;
834                         DEBUG(10,("replaced with special owner ace\n"));
835                 }
836
837                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
838                     ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
839                     ace->who.uid == ownerGID) {
840                         ace->flags |= SMB_ACE4_ID_SPECIAL;
841                         ace->who.special_id = SMB_ACE4_WHO_GROUP;
842                         DEBUG(10,("replaced with special group ace\n"));
843                 }
844         }
845         return true; /* OK */
846 }
847
848 static int smbacl4_substitute_simple(
849         struct SMB4ACL_T *acl,
850         uid_t ownerUID,
851         gid_t ownerGID
852 )
853 {
854         struct SMB4ACE_T *aceint;
855
856         for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
857                 SMB_ACE4PROP_T *ace = &aceint->prop;
858
859                 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
860                           "mask: %x, who: %d\n",
861                           ace->aceType, ace->flags, ace->aceFlags,
862                           ace->aceMask, ace->who.id));
863
864                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
865                     !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
866                     ace->who.uid == ownerUID &&
867                     !nfs_ace_is_inherit(ace)) {
868                         ace->flags |= SMB_ACE4_ID_SPECIAL;
869                         ace->who.special_id = SMB_ACE4_WHO_OWNER;
870                         DEBUG(10,("replaced with special owner ace\n"));
871                 }
872
873                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
874                     ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
875                     ace->who.gid == ownerGID &&
876                     !nfs_ace_is_inherit(ace)) {
877                         ace->flags |= SMB_ACE4_ID_SPECIAL;
878                         ace->who.special_id = SMB_ACE4_WHO_GROUP;
879                         DEBUG(10,("replaced with special group ace\n"));
880                 }
881         }
882         return true; /* OK */
883 }
884
885 static struct SMB4ACL_T *smbacl4_win2nfs4(
886         TALLOC_CTX *mem_ctx,
887         bool is_directory,
888         const struct security_acl *dacl,
889         const struct smbacl4_vfs_params *pparams,
890         uid_t ownerUID,
891         gid_t ownerGID
892 )
893 {
894         struct SMB4ACL_T *theacl;
895         uint32_t i;
896
897         DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
898
899         theacl = smb_create_smb4acl(mem_ctx);
900         if (theacl==NULL)
901                 return NULL;
902
903         for(i=0; i<dacl->num_aces; i++) {
904                 int ret;
905
906                 ret = smbacl4_fill_ace4(is_directory, pparams,
907                                         ownerUID, ownerGID,
908                                         dacl->aces + i, theacl);
909                 if (ret == -1) {
910                         return NULL;
911                 }
912         }
913
914         if (pparams->mode==e_simple) {
915                 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
916         }
917
918         if (pparams->mode==e_special) {
919                 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
920         }
921
922         return theacl;
923 }
924
925 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
926         const struct smbacl4_vfs_params *pparams,
927         uint32_t security_info_sent,
928         const struct security_descriptor *psd,
929         set_nfs4acl_native_fn_t set_nfs4_native)
930 {
931         struct smbacl4_vfs_params params;
932         struct SMB4ACL_T *theacl = NULL;
933         bool    result, is_directory;
934
935         SMB_STRUCT_STAT sbuf;
936         bool set_acl_as_root = false;
937         uid_t newUID = (uid_t)-1;
938         gid_t newGID = (gid_t)-1;
939         int saved_errno;
940         TALLOC_CTX *frame = talloc_stackframe();
941
942         DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
943
944         if ((security_info_sent & (SECINFO_DACL |
945                 SECINFO_GROUP | SECINFO_OWNER)) == 0)
946         {
947                 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
948                         security_info_sent));
949                 TALLOC_FREE(frame);
950                 return NT_STATUS_OK; /* won't show error - later to be
951                                       * refined... */
952         }
953
954         if (pparams == NULL) {
955                 /* Special behaviours */
956                 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
957                         TALLOC_FREE(frame);
958                         return NT_STATUS_NO_MEMORY;
959                 }
960                 pparams = &params;
961         }
962
963         if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
964                 TALLOC_FREE(frame);
965                 return map_nt_error_from_unix(errno);
966         }
967
968         is_directory = S_ISDIR(sbuf.st_ex_mode);
969
970         if (pparams->do_chown) {
971                 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
972                 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
973                                                    security_info_sent, psd);
974                 if (!NT_STATUS_IS_OK(status)) {
975                         DEBUG(8, ("unpack_nt_owners failed"));
976                         TALLOC_FREE(frame);
977                         return status;
978                 }
979                 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
980                     ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
981
982                         status = try_chown(fsp, newUID, newGID);
983                         if (!NT_STATUS_IS_OK(status)) {
984                                 DEBUG(3,("chown %s, %u, %u failed. Error = "
985                                          "%s.\n", fsp_str_dbg(fsp),
986                                          (unsigned int)newUID,
987                                          (unsigned int)newGID,
988                                          nt_errstr(status)));
989                                 TALLOC_FREE(frame);
990                                 return status;
991                         }
992
993                         DEBUG(10,("chown %s, %u, %u succeeded.\n",
994                                   fsp_str_dbg(fsp), (unsigned int)newUID,
995                                   (unsigned int)newGID));
996                         if (smbacl4_GetFileOwner(fsp->conn,
997                                                  fsp->fsp_name,
998                                                  &sbuf)){
999                                 TALLOC_FREE(frame);
1000                                 return map_nt_error_from_unix(errno);
1001                         }
1002
1003                         /* If we successfully chowned, we know we must
1004                          * be able to set the acl, so do it as root.
1005                          */
1006                         set_acl_as_root = true;
1007                 }
1008         }
1009
1010         if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1011                 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1012                            security_info_sent));
1013                 TALLOC_FREE(frame);
1014                 return NT_STATUS_OK;
1015         }
1016
1017         theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams,
1018                                   sbuf.st_ex_uid, sbuf.st_ex_gid);
1019         if (!theacl) {
1020                 TALLOC_FREE(frame);
1021                 return map_nt_error_from_unix(errno);
1022         }
1023
1024         smbacl4_set_controlflags(theacl, psd->type);
1025         smbacl4_dump_nfs4acl(10, theacl);
1026
1027         if (set_acl_as_root) {
1028                 become_root();
1029         }
1030         result = set_nfs4_native(handle, fsp, theacl);
1031         saved_errno = errno;
1032         if (set_acl_as_root) {
1033                 unbecome_root();
1034         }
1035
1036         TALLOC_FREE(frame);
1037
1038         if (result!=true) {
1039                 errno = saved_errno;
1040                 DEBUG(10, ("set_nfs4_native failed with %s\n",
1041                            strerror(errno)));
1042                 return map_nt_error_from_unix(errno);
1043         }
1044
1045         DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1046         return NT_STATUS_OK;
1047 }