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