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