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