s3: Change smbacl4_get_vfs_params to use connection_struct instead of fsp.
[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, SMB4ACL_T *theacl, /* in */
311         struct dom_sid *psid_owner, /* in */
312         struct dom_sid *psid_group, /* in */
313         bool is_directory, /* in */
314         struct security_ace **ppnt_ace_list, /* out */
315         int *pgood_aces /* out */
316 )
317 {
318         SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
319         SMB_ACE4_INT_T *aceint;
320         struct security_ace *nt_ace_list = NULL;
321         int good_aces = 0;
322
323         DEBUG(10, ("smbacl_nfs42win entered\n"));
324
325         aclint = get_validated_aclint(theacl);
326         /* We do not check for naces being 0 or theacl being NULL here
327          * because it is done upstream */
328         /* in smb_get_nt_acl_nfs4(). */
329         nt_ace_list = (struct security_ace *)TALLOC_ZERO_SIZE(
330                 mem_ctx, aclint->naces * sizeof(struct security_ace));
331         if (nt_ace_list==NULL)
332         {
333                 DEBUG(10, ("talloc error"));
334                 errno = ENOMEM;
335                 return False;
336         }
337
338         for (aceint=aclint->first;
339              aceint!=NULL;
340              aceint=(SMB_ACE4_INT_T *)aceint->next) {
341                 uint32_t mask;
342                 struct dom_sid sid;
343                 SMB_ACE4PROP_T  *ace = &aceint->prop;
344                 uint32_t win_ace_flags;
345
346                 DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, "
347                            "mask: %x, who: %d\n",
348                            aceint->magic, ace->aceType, ace->flags,
349                            ace->aceFlags, ace->aceMask, ace->who.id));
350
351                 SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
352
353                 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
354                         switch (ace->who.special_id) {
355                         case SMB_ACE4_WHO_OWNER:
356                                 sid_copy(&sid, psid_owner);
357                                 break;
358                         case SMB_ACE4_WHO_GROUP:
359                                 sid_copy(&sid, psid_group);
360                                 break;
361                         case SMB_ACE4_WHO_EVERYONE:
362                                 sid_copy(&sid, &global_sid_World);
363                                 break;
364                         default:
365                                 DEBUG(8, ("invalid special who id %d "
366                                         "ignored\n", ace->who.special_id));
367                                 continue;
368                         }
369                 } else {
370                         if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
371                                 gid_to_sid(&sid, ace->who.gid);
372                         } else {
373                                 uid_to_sid(&sid, ace->who.uid);
374                         }
375                 }
376                 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
377                            sid_string_dbg(&sid)));
378
379                 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
380                         ace->aceMask |= SMB_ACE4_DELETE_CHILD;
381                 }
382
383                 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
384                         ace->aceFlags);
385                 if (!is_directory &&
386                     (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
387                                       SEC_ACE_FLAG_CONTAINER_INHERIT))) {
388                         /*
389                          * GPFS sets inherits dir_inhert and file_inherit flags
390                          * to files, too, which confuses windows, and seems to
391                          * be wrong anyways. ==> Map these bits away for files.
392                          */
393                         DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
394                         win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
395                                            SEC_ACE_FLAG_CONTAINER_INHERIT);
396                 }
397                 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
398                       ace->aceFlags, win_ace_flags));
399
400                 mask = ace->aceMask;
401                 /* Windows clients expect SYNC on acls to
402                    correctly allow rename. See bug #7909. */
403                 /* But not on DENY ace entries. See
404                    bug #8442. */
405                 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
406                         mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
407                 }
408                 init_sec_ace(&nt_ace_list[good_aces++], &sid,
409                         ace->aceType, mask,
410                         win_ace_flags);
411         }
412
413         *ppnt_ace_list = nt_ace_list;
414         *pgood_aces = good_aces;
415
416         return True;
417 }
418
419 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
420                                            uint32 security_info, TALLOC_CTX *mem_ctx,
421         struct security_descriptor **ppdesc, SMB4ACL_T *theacl)
422 {
423         int     good_aces = 0;
424         struct dom_sid sid_owner, sid_group;
425         size_t sd_size = 0;
426         struct security_ace *nt_ace_list = NULL;
427         struct security_acl *psa = NULL;
428         TALLOC_CTX *frame = talloc_stackframe();
429
430         if (theacl==NULL || smb_get_naces(theacl)==0) {
431                 TALLOC_FREE(frame);
432                 return NT_STATUS_ACCESS_DENIED; /* special because we
433                                                  * shouldn't alloc 0 for
434                                                  * win */
435         }
436
437         uid_to_sid(&sid_owner, sbuf->st_ex_uid);
438         gid_to_sid(&sid_group, sbuf->st_ex_gid);
439
440         if (smbacl4_nfs42win(mem_ctx, theacl, &sid_owner, &sid_group,
441                              S_ISDIR(sbuf->st_ex_mode),
442                                 &nt_ace_list, &good_aces)==False) {
443                 DEBUG(8,("smbacl4_nfs42win failed\n"));
444                 TALLOC_FREE(frame);
445                 return map_nt_error_from_unix(errno);
446         }
447
448         psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
449         if (psa == NULL) {
450                 DEBUG(2,("make_sec_acl failed\n"));
451                 TALLOC_FREE(frame);
452                 return NT_STATUS_NO_MEMORY;
453         }
454
455         DEBUG(10,("after make sec_acl\n"));
456         *ppdesc = make_sec_desc(
457                 mem_ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
458                 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
459                 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
460                 NULL, psa, &sd_size);
461         if (*ppdesc==NULL) {
462                 DEBUG(2,("make_sec_desc failed\n"));
463                 TALLOC_FREE(frame);
464                 return NT_STATUS_NO_MEMORY;
465         }
466
467         DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
468                    "sd_size %d\n",
469                    (int)ndr_size_security_descriptor(*ppdesc, 0)));
470
471         TALLOC_FREE(frame);
472         return NT_STATUS_OK;
473 }
474
475 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
476                               uint32 security_info,
477                               TALLOC_CTX *mem_ctx,
478                               struct security_descriptor **ppdesc,
479                               SMB4ACL_T *theacl)
480 {
481         SMB_STRUCT_STAT sbuf;
482
483         DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
484
485         if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
486                 return map_nt_error_from_unix(errno);
487         }
488
489         return smb_get_nt_acl_nfs4_common(&sbuf, security_info,
490                                           mem_ctx, ppdesc,
491                                           theacl);
492 }
493
494 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
495                              const char *name,
496                              uint32 security_info,
497                              TALLOC_CTX *mem_ctx,
498                              struct security_descriptor **ppdesc,
499                              SMB4ACL_T *theacl)
500 {
501         SMB_STRUCT_STAT sbuf;
502
503         DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
504
505         if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
506                 return map_nt_error_from_unix(errno);
507         }
508
509         return smb_get_nt_acl_nfs4_common(&sbuf, security_info,
510                                           mem_ctx, ppdesc,
511                                           theacl);
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,
769                                    fsp->conn, &params)) {
770                 TALLOC_FREE(frame);
771                 return NT_STATUS_NO_MEMORY;
772         }
773
774         if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
775                 TALLOC_FREE(frame);
776                 return map_nt_error_from_unix(errno);
777         }
778
779         if (params.do_chown) {
780                 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
781                 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
782                                                    security_info_sent, psd);
783                 if (!NT_STATUS_IS_OK(status)) {
784                         DEBUG(8, ("unpack_nt_owners failed"));
785                         TALLOC_FREE(frame);
786                         return status;
787                 }
788                 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
789                     ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
790
791                         status = try_chown(fsp, newUID, newGID);
792                         if (!NT_STATUS_IS_OK(status)) {
793                                 DEBUG(3,("chown %s, %u, %u failed. Error = "
794                                          "%s.\n", fsp_str_dbg(fsp),
795                                          (unsigned int)newUID,
796                                          (unsigned int)newGID,
797                                          nt_errstr(status)));
798                                 TALLOC_FREE(frame);
799                                 return status;
800                         }
801
802                         DEBUG(10,("chown %s, %u, %u succeeded.\n",
803                                   fsp_str_dbg(fsp), (unsigned int)newUID,
804                                   (unsigned int)newGID));
805                         if (smbacl4_GetFileOwner(fsp->conn,
806                                                  fsp->fsp_name->base_name,
807                                                  &sbuf))
808                                 TALLOC_FREE(frame);
809                                 return map_nt_error_from_unix(errno);
810
811                         /* If we successfully chowned, we know we must
812                          * be able to set the acl, so do it as root.
813                          */
814                         set_acl_as_root = true;
815                 }
816         }
817
818         if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
819                 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
820                            security_info_sent));
821                 TALLOC_FREE(frame);
822                 return NT_STATUS_OK;
823         }
824
825         theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, &params,
826                                   sbuf.st_ex_uid, sbuf.st_ex_gid);
827         if (!theacl) {
828                 TALLOC_FREE(frame);
829                 return map_nt_error_from_unix(errno);
830         }
831
832         smbacl4_dump_nfs4acl(10, theacl);
833
834         if (set_acl_as_root) {
835                 become_root();
836         }
837         result = set_nfs4_native(handle, fsp, theacl);
838         saved_errno = errno;
839         if (set_acl_as_root) {
840                 unbecome_root();
841         }
842
843         TALLOC_FREE(frame);
844
845         if (result!=True) {
846                 errno = saved_errno;
847                 DEBUG(10, ("set_nfs4_native failed with %s\n",
848                            strerror(errno)));
849                 return map_nt_error_from_unix(errno);
850         }
851
852         DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
853         return NT_STATUS_OK;
854 }