nfs4_acls: Rename smbacl4_fill_ace4 function
[autobuild.flakey.sn-devel-184/.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 static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup,
658                                      struct SMB4ACL_T *theacl,
659                                      SMB_ACE4PROP_T *ace,
660                                      bool *paddNewACE)
661 {
662         int     result = 0;
663         SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
664         if (ace4found)
665         {
666                 switch(acedup)
667                 {
668                 case e_merge: /* "merge" flags */
669                         *paddNewACE = false;
670                         ace4found->aceFlags |= ace->aceFlags;
671                         ace4found->aceMask |= ace->aceMask;
672                         break;
673                 case e_ignore: /* leave out this record */
674                         *paddNewACE = false;
675                         break;
676                 case e_reject: /* do an error */
677                         DBG_INFO("ACL rejected by duplicate nt ace.\n");
678                         errno = EINVAL; /* SHOULD be set on any _real_ error */
679                         result = -1;
680                         break;
681                 default:
682                         break;
683                 }
684         }
685         return result;
686 }
687
688 static int nfs4_acl_add_ace(enum smbacl4_acedup_enum acedup,
689                             struct SMB4ACL_T *nfs4_acl,
690                             SMB_ACE4PROP_T *nfs4_ace)
691 {
692         bool add_ace = true;
693
694         if (acedup != e_dontcare) {
695                 int ret;
696
697                 ret = smbacl4_MergeIgnoreReject(acedup, nfs4_acl,
698                                                 nfs4_ace, &add_ace);
699                 if (ret == -1) {
700                         return -1;
701                 }
702         }
703
704         if (add_ace) {
705                 smb_add_ace4(nfs4_acl, nfs4_ace);
706         }
707
708         return 0;
709 }
710
711 static int nfs4_acl_add_sec_ace(bool is_directory,
712                                 const struct smbacl4_vfs_params *params,
713                                 uid_t ownerUID,
714                                 gid_t ownerGID,
715                                 const struct security_ace *ace_nt,
716                                 struct SMB4ACL_T *nfs4_acl)
717 {
718         struct dom_sid_buf buf;
719         SMB_ACE4PROP_T nfs4_ace = { 0 };
720         SMB_ACE4PROP_T nfs4_ace_2 = { 0 };
721         bool add_ace2 = false;
722         int ret;
723
724         DEBUG(10, ("got ace for %s\n",
725                    dom_sid_str_buf(&ace_nt->trustee, &buf)));
726
727         /* only ACCESS|DENY supported right now */
728         nfs4_ace.aceType = ace_nt->type;
729
730         nfs4_ace.aceFlags =
731                 map_windows_ace_flags_to_nfs4_ace_flags(ace_nt->flags);
732
733         /* remove inheritance flags on files */
734         if (!is_directory) {
735                 DEBUG(10, ("Removing inheritance flags from a file\n"));
736                 nfs4_ace.aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
737                                        SMB_ACE4_DIRECTORY_INHERIT_ACE|
738                                        SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
739                                        SMB_ACE4_INHERIT_ONLY_ACE);
740         }
741
742         nfs4_ace.aceMask = ace_nt->access_mask & (SEC_STD_ALL | SEC_FILE_ALL);
743
744         se_map_generic(&nfs4_ace.aceMask, &file_generic_mapping);
745
746         if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
747                 nfs4_ace.who.special_id = SMB_ACE4_WHO_EVERYONE;
748                 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
749         } else if (params->mode!=e_special &&
750                    dom_sid_equal(&ace_nt->trustee,
751                                  &global_sid_Creator_Owner)) {
752                 DEBUG(10, ("Map creator owner\n"));
753                 nfs4_ace.who.special_id = SMB_ACE4_WHO_OWNER;
754                 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
755                 /* A non inheriting creator owner entry has no effect. */
756                 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
757                 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
758                     && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
759                         return 0;
760                 }
761         } else if (params->mode!=e_special &&
762                    dom_sid_equal(&ace_nt->trustee,
763                                  &global_sid_Creator_Group)) {
764                 DEBUG(10, ("Map creator owner group\n"));
765                 nfs4_ace.who.special_id = SMB_ACE4_WHO_GROUP;
766                 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
767                 /* A non inheriting creator group entry has no effect. */
768                 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
769                 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
770                     && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
771                         return 0;
772                 }
773         } else {
774                 struct unixid unixid;
775                 bool ok;
776
777                 ok = sids_to_unixids(&ace_nt->trustee, 1, &unixid);
778                 if (!ok) {
779                         DBG_WARNING("Could not convert %s to uid or gid.\n",
780                                     dom_sid_str_buf(&ace_nt->trustee, &buf));
781                         return 0;
782                 }
783
784                 if (dom_sid_compare_domain(&ace_nt->trustee,
785                                            &global_sid_Unix_NFS) == 0) {
786                         return 0;
787                 }
788
789                 switch (unixid.type) {
790                 case ID_TYPE_BOTH:
791                         nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
792                         nfs4_ace.who.gid = unixid.id;
793
794                         if (ownerUID == unixid.id &&
795                             !nfs_ace_is_inherit(&nfs4_ace))
796                         {
797                                 /*
798                                  * IDMAP_TYPE_BOTH for owner. Add
799                                  * additional user entry, which can be
800                                  * mapped to special:owner to reflect
801                                  * the permissions in the modebits.
802                                  *
803                                  * This only applies to non-inheriting
804                                  * entries as only these are replaced
805                                  * with SPECIAL_OWNER in nfs4:mode=simple.
806                                  */
807                                 nfs4_ace_2 = (SMB_ACE4PROP_T) {
808                                         .who.uid = unixid.id,
809                                         .aceFlags = (nfs4_ace.aceFlags &
810                                                     ~SMB_ACE4_IDENTIFIER_GROUP),
811                                         .aceMask = nfs4_ace.aceMask,
812                                         .aceType = nfs4_ace.aceType,
813                                 };
814                                 add_ace2 = true;
815                         }
816                         break;
817                 case ID_TYPE_GID:
818                         nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
819                         nfs4_ace.who.gid = unixid.id;
820                         break;
821                 case ID_TYPE_UID:
822                         nfs4_ace.who.uid = unixid.id;
823                         break;
824                 case ID_TYPE_NOT_SPECIFIED:
825                 default:
826                         DBG_WARNING("Could not convert %s to uid or gid.\n",
827                                     dom_sid_str_buf(&ace_nt->trustee, &buf));
828                         return 0;
829                 }
830         }
831
832         ret = nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace);
833         if (ret != 0) {
834                 return -1;
835         }
836
837         if (!add_ace2) {
838                 return 0;
839         }
840
841         return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace_2);
842 }
843
844 static void smbacl4_substitute_special(struct SMB4ACL_T *acl,
845                                        uid_t ownerUID,
846                                        gid_t ownerGID)
847 {
848         struct SMB4ACE_T *aceint;
849
850         for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
851                 SMB_ACE4PROP_T *ace = &aceint->prop;
852
853                 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
854                           "mask: %x, who: %d\n",
855                           ace->aceType, ace->flags, ace->aceFlags,
856                           ace->aceMask, ace->who.id));
857
858                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
859                     !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
860                     ace->who.uid == ownerUID) {
861                         ace->flags |= SMB_ACE4_ID_SPECIAL;
862                         ace->who.special_id = SMB_ACE4_WHO_OWNER;
863                         DEBUG(10,("replaced with special owner ace\n"));
864                 }
865
866                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
867                     ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
868                     ace->who.uid == ownerGID) {
869                         ace->flags |= SMB_ACE4_ID_SPECIAL;
870                         ace->who.special_id = SMB_ACE4_WHO_GROUP;
871                         DEBUG(10,("replaced with special group ace\n"));
872                 }
873         }
874         return true; /* OK */
875 }
876
877 static int smbacl4_substitute_simple(
878         struct SMB4ACL_T *acl,
879         uid_t ownerUID,
880         gid_t ownerGID
881 )
882 {
883         struct SMB4ACE_T *aceint;
884
885         for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
886                 SMB_ACE4PROP_T *ace = &aceint->prop;
887
888                 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
889                           "mask: %x, who: %d\n",
890                           ace->aceType, ace->flags, ace->aceFlags,
891                           ace->aceMask, ace->who.id));
892
893                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
894                     !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
895                     ace->who.uid == ownerUID &&
896                     !nfs_ace_is_inherit(ace)) {
897                         ace->flags |= SMB_ACE4_ID_SPECIAL;
898                         ace->who.special_id = SMB_ACE4_WHO_OWNER;
899                         DEBUG(10,("replaced with special owner ace\n"));
900                 }
901
902                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
903                     ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
904                     ace->who.gid == ownerGID &&
905                     !nfs_ace_is_inherit(ace)) {
906                         ace->flags |= SMB_ACE4_ID_SPECIAL;
907                         ace->who.special_id = SMB_ACE4_WHO_GROUP;
908                         DEBUG(10,("replaced with special group ace\n"));
909                 }
910         }
911         return true; /* OK */
912 }
913
914 static struct SMB4ACL_T *smbacl4_win2nfs4(
915         TALLOC_CTX *mem_ctx,
916         bool is_directory,
917         const struct security_acl *dacl,
918         const struct smbacl4_vfs_params *pparams,
919         uid_t ownerUID,
920         gid_t ownerGID
921 )
922 {
923         struct SMB4ACL_T *theacl;
924         uint32_t i;
925
926         DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
927
928         theacl = smb_create_smb4acl(mem_ctx);
929         if (theacl==NULL)
930                 return NULL;
931
932         for(i=0; i<dacl->num_aces; i++) {
933                 int ret;
934
935                 ret = nfs4_acl_add_sec_ace(is_directory, pparams,
936                                            ownerUID, ownerGID,
937                                            dacl->aces + i, theacl);
938                 if (ret == -1) {
939                         return NULL;
940                 }
941         }
942
943         if (pparams->mode==e_simple) {
944                 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
945         }
946
947         if (pparams->mode==e_special) {
948                 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
949         }
950
951         return theacl;
952 }
953
954 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
955         const struct smbacl4_vfs_params *pparams,
956         uint32_t security_info_sent,
957         const struct security_descriptor *psd,
958         set_nfs4acl_native_fn_t set_nfs4_native)
959 {
960         struct smbacl4_vfs_params params;
961         struct SMB4ACL_T *theacl = NULL;
962         bool    result, is_directory;
963
964         SMB_STRUCT_STAT sbuf;
965         bool set_acl_as_root = false;
966         uid_t newUID = (uid_t)-1;
967         gid_t newGID = (gid_t)-1;
968         int saved_errno;
969         TALLOC_CTX *frame = talloc_stackframe();
970
971         DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
972
973         if ((security_info_sent & (SECINFO_DACL |
974                 SECINFO_GROUP | SECINFO_OWNER)) == 0)
975         {
976                 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
977                         security_info_sent));
978                 TALLOC_FREE(frame);
979                 return NT_STATUS_OK; /* won't show error - later to be
980                                       * refined... */
981         }
982
983         if (pparams == NULL) {
984                 /* Special behaviours */
985                 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
986                         TALLOC_FREE(frame);
987                         return NT_STATUS_NO_MEMORY;
988                 }
989                 pparams = &params;
990         }
991
992         if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
993                 TALLOC_FREE(frame);
994                 return map_nt_error_from_unix(errno);
995         }
996
997         is_directory = S_ISDIR(sbuf.st_ex_mode);
998
999         if (pparams->do_chown) {
1000                 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
1001                 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
1002                                                    security_info_sent, psd);
1003                 if (!NT_STATUS_IS_OK(status)) {
1004                         DEBUG(8, ("unpack_nt_owners failed"));
1005                         TALLOC_FREE(frame);
1006                         return status;
1007                 }
1008                 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
1009                     ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
1010
1011                         status = try_chown(fsp, newUID, newGID);
1012                         if (!NT_STATUS_IS_OK(status)) {
1013                                 DEBUG(3,("chown %s, %u, %u failed. Error = "
1014                                          "%s.\n", fsp_str_dbg(fsp),
1015                                          (unsigned int)newUID,
1016                                          (unsigned int)newGID,
1017                                          nt_errstr(status)));
1018                                 TALLOC_FREE(frame);
1019                                 return status;
1020                         }
1021
1022                         DEBUG(10,("chown %s, %u, %u succeeded.\n",
1023                                   fsp_str_dbg(fsp), (unsigned int)newUID,
1024                                   (unsigned int)newGID));
1025                         if (smbacl4_GetFileOwner(fsp->conn,
1026                                                  fsp->fsp_name,
1027                                                  &sbuf)){
1028                                 TALLOC_FREE(frame);
1029                                 return map_nt_error_from_unix(errno);
1030                         }
1031
1032                         /* If we successfully chowned, we know we must
1033                          * be able to set the acl, so do it as root.
1034                          */
1035                         set_acl_as_root = true;
1036                 }
1037         }
1038
1039         if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1040                 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1041                            security_info_sent));
1042                 TALLOC_FREE(frame);
1043                 return NT_STATUS_OK;
1044         }
1045
1046         theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams,
1047                                   sbuf.st_ex_uid, sbuf.st_ex_gid);
1048         if (!theacl) {
1049                 TALLOC_FREE(frame);
1050                 return map_nt_error_from_unix(errno);
1051         }
1052
1053         smbacl4_set_controlflags(theacl, psd->type);
1054         smbacl4_dump_nfs4acl(10, theacl);
1055
1056         if (set_acl_as_root) {
1057                 become_root();
1058         }
1059         result = set_nfs4_native(handle, fsp, theacl);
1060         saved_errno = errno;
1061         if (set_acl_as_root) {
1062                 unbecome_root();
1063         }
1064
1065         TALLOC_FREE(frame);
1066
1067         if (result!=true) {
1068                 errno = saved_errno;
1069                 DEBUG(10, ("set_nfs4_native failed with %s\n",
1070                            strerror(errno)));
1071                 return map_nt_error_from_unix(errno);
1072         }
1073
1074         DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1075         return NT_STATUS_OK;
1076 }