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