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