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