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