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