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