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