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