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