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