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