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