s3: Use mode bits in some cases in mode simple.
[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 #define SMB_ACE4_INT_MAGIC 0x76F8A967
41 typedef struct _SMB_ACE4_INT_T
42 {
43         uint32  magic;
44         SMB_ACE4PROP_T  prop;
45         void    *next;
46 } SMB_ACE4_INT_T;
47
48 #define SMB_ACL4_INT_MAGIC 0x29A3E792
49 typedef struct _SMB_ACL4_INT_T
50 {
51         uint32  magic;
52         uint32  naces;
53         SMB_ACE4_INT_T  *first;
54         SMB_ACE4_INT_T  *last;
55 } SMB_ACL4_INT_T;
56
57 enum smbacl4_mode_enum {e_simple=0, e_special=1};
58 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
59
60 typedef struct _smbacl4_vfs_params {
61         enum smbacl4_mode_enum mode;
62         bool do_chown;
63         enum smbacl4_acedup_enum acedup;
64 } smbacl4_vfs_params;
65
66 /*
67  * Gather special parameters for NFS4 ACL handling
68  */
69 static int smbacl4_get_vfs_params(
70         const char *type_name,
71         struct connection_struct *conn,
72         smbacl4_vfs_params *params
73 )
74 {
75         static const struct enum_list enum_smbacl4_modes[] = {
76                 { e_simple, "simple" },
77                 { e_special, "special" },
78                 { -1 , NULL }
79         };
80         static const struct enum_list enum_smbacl4_acedups[] = {
81                 { e_dontcare, "dontcare" },
82                 { e_reject, "reject" },
83                 { e_ignore, "ignore" },
84                 { e_merge, "merge" },
85                 { -1 , NULL }
86         };
87
88         memset(params, 0, sizeof(smbacl4_vfs_params));
89         params->mode = (enum smbacl4_mode_enum)lp_parm_enum(
90                 SNUM(conn), type_name,
91                 "mode", enum_smbacl4_modes, e_simple);
92         params->do_chown = lp_parm_bool(SNUM(conn), type_name,
93                 "chown", true);
94         params->acedup = (enum smbacl4_acedup_enum)lp_parm_enum(
95                 SNUM(conn), type_name,
96                 "acedup", enum_smbacl4_acedups, e_dontcare);
97
98         DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s\n",
99                 enum_smbacl4_modes[params->mode].name,
100                 params->do_chown ? "true" : "false",
101                 enum_smbacl4_acedups[params->acedup].name));
102
103         return 0;
104 }
105
106 /************************************************
107  Split the ACE flag mapping between nfs4 and Windows
108  into two separate functions rather than trying to do
109  it inline. Allows us to carefully control what flags
110  are mapped to what in one place.
111 ************************************************/
112
113 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
114         uint32_t nfs4_ace_flags)
115 {
116         uint32_t win_ace_flags = 0;
117
118         /* The nfs4 flags <= 0xf map perfectly. */
119         win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
120                                       SEC_ACE_FLAG_CONTAINER_INHERIT|
121                                       SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
122                                       SEC_ACE_FLAG_INHERIT_ONLY);
123
124         /* flags greater than 0xf have diverged :-(. */
125         /* See the nfs4 ace flag definitions here:
126            http://www.ietf.org/rfc/rfc3530.txt.
127            And the Windows ace flag definitions here:
128            librpc/idl/security.idl. */
129         if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
130                 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
131         }
132
133         return win_ace_flags;
134 }
135
136 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
137 {
138         uint32_t nfs4_ace_flags = 0;
139
140         /* The windows flags <= 0xf map perfectly. */
141         nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
142                                       SMB_ACE4_DIRECTORY_INHERIT_ACE|
143                                       SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
144                                       SMB_ACE4_INHERIT_ONLY_ACE);
145
146         /* flags greater than 0xf have diverged :-(. */
147         /* See the nfs4 ace flag definitions here:
148            http://www.ietf.org/rfc/rfc3530.txt.
149            And the Windows ace flag definitions here:
150            librpc/idl/security.idl. */
151         if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
152                 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
153         }
154
155         return nfs4_ace_flags;
156 }
157
158 static SMB_ACL4_INT_T *get_validated_aclint(SMB4ACL_T *theacl)
159 {
160         SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
161         if (theacl==NULL)
162         {
163                 DEBUG(2, ("acl is NULL\n"));
164                 errno = EINVAL;
165                 return NULL;
166         }
167         if (aclint->magic!=SMB_ACL4_INT_MAGIC)
168         {
169                 DEBUG(2, ("aclint bad magic 0x%x\n", aclint->magic));
170                 errno = EINVAL;
171                 return NULL;
172         }
173         return aclint;
174 }
175
176 static SMB_ACE4_INT_T *get_validated_aceint(SMB4ACE_T *ace)
177 {
178         SMB_ACE4_INT_T *aceint = (SMB_ACE4_INT_T *)ace;
179         if (ace==NULL)
180         {
181                 DEBUG(2, ("ace is NULL\n"));
182                 errno = EINVAL;
183                 return NULL;
184         }
185         if (aceint->magic!=SMB_ACE4_INT_MAGIC)
186         {
187                 DEBUG(2, ("aceint bad magic 0x%x\n", aceint->magic));
188                 errno = EINVAL;
189                 return NULL;
190         }
191         return aceint;
192 }
193
194 SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
195 {
196         SMB_ACL4_INT_T  *theacl = (SMB_ACL4_INT_T *)TALLOC_ZERO_SIZE(
197                 mem_ctx, sizeof(SMB_ACL4_INT_T));
198         if (theacl==NULL)
199         {
200                 DEBUG(0, ("TALLOC_SIZE failed\n"));
201                 errno = ENOMEM;
202                 return NULL;
203         }
204         theacl->magic = SMB_ACL4_INT_MAGIC;
205         /* theacl->first, last = NULL not needed */
206         return (SMB4ACL_T *)theacl;
207 }
208
209 SMB4ACE_T *smb_add_ace4(SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop)
210 {
211         SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
212         SMB_ACE4_INT_T *ace;
213
214         ace = (SMB_ACE4_INT_T *)TALLOC_ZERO_SIZE(
215                 theacl, sizeof(SMB_ACE4_INT_T));
216         if (ace==NULL)
217         {
218                 DEBUG(0, ("TALLOC_SIZE failed\n"));
219                 errno = ENOMEM;
220                 return NULL;
221         }
222         ace->magic = SMB_ACE4_INT_MAGIC;
223         /* ace->next = NULL not needed */
224         memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
225
226         if (aclint->first==NULL)
227         {
228                 aclint->first = ace;
229                 aclint->last = ace;
230         } else {
231                 aclint->last->next = (void *)ace;
232                 aclint->last = ace;
233         }
234         aclint->naces++;
235
236         return (SMB4ACE_T *)ace;
237 }
238
239 SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace)
240 {
241         SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
242         if (aceint==NULL)
243                 return NULL;
244
245         return &aceint->prop;
246 }
247
248 SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace)
249 {
250         SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
251         if (aceint==NULL)
252                 return NULL;
253
254         return (SMB4ACE_T *)aceint->next;
255 }
256
257 SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl)
258 {
259         SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
260         if (aclint==NULL)
261                 return NULL;
262
263         return (SMB4ACE_T *)aclint->first;
264 }
265
266 uint32 smb_get_naces(SMB4ACL_T *theacl)
267 {
268         SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
269         if (aclint==NULL)
270                 return 0;
271
272         return aclint->naces;
273 }
274
275 static int smbacl4_GetFileOwner(struct connection_struct *conn,
276                                 const char *filename,
277                                 SMB_STRUCT_STAT *psbuf)
278 {
279         memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
280
281         /* Get the stat struct for the owner info. */
282         if (vfs_stat_smb_fname(conn, filename, psbuf) != 0)
283         {
284                 DEBUG(8, ("vfs_stat_smb_fname failed with error %s\n",
285                         strerror(errno)));
286                 return -1;
287         }
288
289         return 0;
290 }
291
292 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
293 {
294         memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
295
296         if (fsp->fh->fd == -1) {
297                 return smbacl4_GetFileOwner(fsp->conn,
298                                             fsp->fsp_name->base_name, psbuf);
299         }
300         if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
301         {
302                 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
303                         strerror(errno)));
304                 return -1;
305         }
306
307         return 0;
308 }
309
310 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
311         smbacl4_vfs_params *params,
312         SMB4ACL_T *theacl, /* in */
313         struct dom_sid *psid_owner, /* in */
314         struct dom_sid *psid_group, /* in */
315         bool is_directory, /* in */
316         struct security_ace **ppnt_ace_list, /* out */
317         int *pgood_aces /* out */
318 )
319 {
320         SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
321         SMB_ACE4_INT_T *aceint;
322         struct security_ace *nt_ace_list = NULL;
323         int good_aces = 0;
324
325         DEBUG(10, ("smbacl_nfs42win entered\n"));
326
327         aclint = get_validated_aclint(theacl);
328         /* We do not check for naces being 0 or theacl being NULL here
329            because it is done upstream in smb_get_nt_acl_nfs4().
330            We reserve twice the number of input aces because one nfs4
331            ace might result in 2 nt aces.*/
332         nt_ace_list = (struct security_ace *)TALLOC_ZERO_SIZE(
333                 mem_ctx, 2 * aclint->naces * sizeof(struct security_ace));
334         if (nt_ace_list==NULL)
335         {
336                 DEBUG(10, ("talloc error"));
337                 errno = ENOMEM;
338                 return False;
339         }
340
341         for (aceint=aclint->first;
342              aceint!=NULL;
343              aceint=(SMB_ACE4_INT_T *)aceint->next) {
344                 uint32_t mask;
345                 struct dom_sid sid;
346                 SMB_ACE4PROP_T  *ace = &aceint->prop;
347                 uint32_t win_ace_flags;
348
349                 DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, "
350                            "mask: %x, who: %d\n",
351                            aceint->magic, ace->aceType, ace->flags,
352                            ace->aceFlags, ace->aceMask, ace->who.id));
353
354                 SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
355
356                 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
357                         switch (ace->who.special_id) {
358                         case SMB_ACE4_WHO_OWNER:
359                                 sid_copy(&sid, psid_owner);
360                                 break;
361                         case SMB_ACE4_WHO_GROUP:
362                                 sid_copy(&sid, psid_group);
363                                 break;
364                         case SMB_ACE4_WHO_EVERYONE:
365                                 sid_copy(&sid, &global_sid_World);
366                                 break;
367                         default:
368                                 DEBUG(8, ("invalid special who id %d "
369                                         "ignored\n", ace->who.special_id));
370                                 continue;
371                         }
372                 } else {
373                         if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
374                                 gid_to_sid(&sid, ace->who.gid);
375                         } else {
376                                 uid_to_sid(&sid, ace->who.uid);
377                         }
378                 }
379                 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
380                            sid_string_dbg(&sid)));
381
382                 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
383                         ace->aceMask |= SMB_ACE4_DELETE_CHILD;
384                 }
385
386                 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
387                         ace->aceFlags);
388                 if (!is_directory &&
389                     (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
390                                       SEC_ACE_FLAG_CONTAINER_INHERIT))) {
391                         /*
392                          * GPFS sets inherits dir_inhert and file_inherit flags
393                          * to files, too, which confuses windows, and seems to
394                          * be wrong anyways. ==> Map these bits away for files.
395                          */
396                         DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
397                         win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
398                                            SEC_ACE_FLAG_CONTAINER_INHERIT);
399                 }
400                 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
401                       ace->aceFlags, win_ace_flags));
402
403                 mask = ace->aceMask;
404                 /* Windows clients expect SYNC on acls to
405                    correctly allow rename. See bug #7909. */
406                 /* But not on DENY ace entries. See
407                    bug #8442. */
408                 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
409                         mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
410                 }
411
412                 /* Mapping of owner@ and group@ to creator owner and
413                    creator group. Keep old behavior in mode special. */
414                 if (params->mode != e_special &&
415                     ace->flags & SMB_ACE4_ID_SPECIAL &&
416                     (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
417                      ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
418                         DEBUG(10, ("Map special entry\n"));
419                         if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
420                                 DEBUG(10, ("Map current sid\n"));
421                                 uint32_t win_ace_flags_current;
422                                 win_ace_flags_current = win_ace_flags &
423                                         ~(SEC_ACE_FLAG_OBJECT_INHERIT |
424                                           SEC_ACE_FLAG_CONTAINER_INHERIT);
425                                 init_sec_ace(&nt_ace_list[good_aces++], &sid,
426                                              ace->aceType, mask,
427                                              win_ace_flags_current);
428                         }
429                         if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
430                             win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
431                                              SEC_ACE_FLAG_CONTAINER_INHERIT)) {
432                                 uint32_t win_ace_flags_creator;
433                                 DEBUG(10, ("Map creator owner\n"));
434                                 win_ace_flags_creator = win_ace_flags |
435                                         SMB_ACE4_INHERIT_ONLY_ACE;
436                                 init_sec_ace(&nt_ace_list[good_aces++],
437                                              &global_sid_Creator_Owner,
438                                              ace->aceType, mask,
439                                              win_ace_flags_creator);
440                         }
441                         if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
442                             win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
443                                              SEC_ACE_FLAG_CONTAINER_INHERIT)) {
444                                 uint32_t win_ace_flags_creator;
445                                 DEBUG(10, ("Map creator owner group\n"));
446                                 win_ace_flags_creator = win_ace_flags |
447                                         SMB_ACE4_INHERIT_ONLY_ACE;
448                                 init_sec_ace(&nt_ace_list[good_aces++],
449                                              &global_sid_Creator_Group,
450                                              ace->aceType, mask,
451                                              win_ace_flags_creator);
452                         }
453                 } else {
454                         DEBUG(10, ("Map normal sid\n"));
455                         init_sec_ace(&nt_ace_list[good_aces++], &sid,
456                                      ace->aceType, mask,
457                                      win_ace_flags);
458                 }
459         }
460
461         nt_ace_list = (struct security_ace *)TALLOC_REALLOC(mem_ctx,
462                                         nt_ace_list,
463                                         good_aces * sizeof(struct security_ace));
464         if (nt_ace_list == NULL) {
465                 errno = ENOMEM;
466                 return false;
467         }
468
469         *ppnt_ace_list = nt_ace_list;
470         *pgood_aces = good_aces;
471
472         return True;
473 }
474
475 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
476                                            smbacl4_vfs_params *params,
477                                            uint32 security_info,
478                                            TALLOC_CTX *mem_ctx,
479                                            struct security_descriptor **ppdesc,
480                                            SMB4ACL_T *theacl)
481 {
482         int good_aces = 0;
483         struct dom_sid sid_owner, sid_group;
484         size_t sd_size = 0;
485         struct security_ace *nt_ace_list = NULL;
486         struct security_acl *psa = NULL;
487         TALLOC_CTX *frame = talloc_stackframe();
488
489         if (theacl==NULL || smb_get_naces(theacl)==0) {
490                 TALLOC_FREE(frame);
491                 return NT_STATUS_ACCESS_DENIED; /* special because we
492                                                  * shouldn't alloc 0 for
493                                                  * win */
494         }
495
496         uid_to_sid(&sid_owner, sbuf->st_ex_uid);
497         gid_to_sid(&sid_group, sbuf->st_ex_gid);
498
499         if (smbacl4_nfs42win(mem_ctx, params, theacl, &sid_owner, &sid_group,
500                              S_ISDIR(sbuf->st_ex_mode),
501                                 &nt_ace_list, &good_aces)==False) {
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, SEC_DESC_SELF_RELATIVE,
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 security_info,
536                               TALLOC_CTX *mem_ctx,
537                               struct security_descriptor **ppdesc,
538                               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 security_info,
561                              TALLOC_CTX *mem_ctx,
562                              struct security_descriptor **ppdesc,
563                              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, SMB4ACL_T *theacl)
584 {
585         SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
586         SMB_ACE4_INT_T *aceint;
587
588         DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
589
590         for (aceint = aclint->first;
591              aceint!=NULL;
592              aceint=(SMB_ACE4_INT_T *)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         SMB4ACL_T *theacl,
611         SMB_ACE4PROP_T *aceNew)
612 {
613         SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
614         SMB_ACE4_INT_T *aceint;
615
616         for (aceint = aclint->first; aceint != NULL;
617              aceint=(SMB_ACE4_INT_T *)aceint->next) {
618                 SMB_ACE4PROP_T *ace = &aceint->prop;
619
620                 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
621                           "new type:0x%x flags:0x%x aceFlags:0x%x\n",
622                           ace->aceType, ace->flags, ace->aceFlags,
623                           aceNew->aceType, aceNew->flags,aceNew->aceFlags));
624
625                 if (ace->flags == aceNew->flags &&
626                         ace->aceType==aceNew->aceType &&
627                         ace->aceFlags==aceNew->aceFlags)
628                 {
629                         /* keep type safety; e.g. gid is an u.short */
630                         if (ace->flags & SMB_ACE4_ID_SPECIAL)
631                         {
632                                 if (ace->who.special_id ==
633                                     aceNew->who.special_id)
634                                         return ace;
635                         } else {
636                                 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
637                                 {
638                                         if (ace->who.gid==aceNew->who.gid)
639                                                 return ace;
640                                 } else {
641                                         if (ace->who.uid==aceNew->who.uid)
642                                                 return ace;
643                                 }
644                         }
645                 }
646         }
647
648         return NULL;
649 }
650
651
652 static bool smbacl4_fill_ace4(
653         const struct smb_filename *filename,
654         smbacl4_vfs_params *params,
655         uid_t ownerUID,
656         gid_t ownerGID,
657         const struct security_ace *ace_nt, /* input */
658         SMB_ACE4PROP_T *ace_v4 /* output */
659 )
660 {
661         DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
662
663         memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
664
665         /* only ACCESS|DENY supported right now */
666         ace_v4->aceType = ace_nt->type;
667
668         ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
669                 ace_nt->flags);
670
671         /* remove inheritance flags on files */
672         if (VALID_STAT(filename->st) &&
673             !S_ISDIR(filename->st.st_ex_mode)) {
674                 DEBUG(10, ("Removing inheritance flags from a file\n"));
675                 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
676                                       SMB_ACE4_DIRECTORY_INHERIT_ACE|
677                                       SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
678                                       SMB_ACE4_INHERIT_ONLY_ACE);
679         }
680
681         ace_v4->aceMask = ace_nt->access_mask &
682                 (SEC_STD_ALL | SEC_FILE_ALL);
683
684         se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
685
686         if (ace_v4->aceFlags!=ace_nt->flags)
687                 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
688                         ace_v4->aceFlags, ace_nt->flags));
689
690         if (ace_v4->aceMask!=ace_nt->access_mask)
691                 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
692                         ace_v4->aceMask, ace_nt->access_mask));
693
694         if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
695                 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
696                 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
697         } else if (params->mode!=e_special &&
698                    dom_sid_equal(&ace_nt->trustee,
699                                  &global_sid_Creator_Owner)) {
700                 DEBUG(10, ("Map creator owner\n"));
701                 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
702                 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
703                 /* A non inheriting creator owner entry has no effect. */
704                 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
705                 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
706                     && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
707                         return False;
708                 }
709         } else if (params->mode!=e_special &&
710                    dom_sid_equal(&ace_nt->trustee,
711                                  &global_sid_Creator_Group)) {
712                 DEBUG(10, ("Map creator owner group\n"));
713                 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
714                 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
715                 /* A non inheriting creator group entry has no effect. */
716                 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
717                 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
718                     && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
719                         return False;
720                 }
721         } else {
722                 uid_t uid;
723                 gid_t gid;
724
725                 if (sid_to_gid(&ace_nt->trustee, &gid)) {
726                         ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
727
728                         if (params->mode==e_special && gid==ownerGID) {
729                                 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
730                                 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
731                         } else {
732                                 ace_v4->who.gid = gid;
733                         }
734                 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
735                         if (params->mode==e_special && uid==ownerUID) {
736                                 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
737                                 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
738                         } else {
739                                 ace_v4->who.uid = uid;
740                         }
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                                   sid_string_dbg(&ace_nt->trustee)));
746                         return False;
747                 }
748         }
749
750         return True; /* OK */
751 }
752
753 static int smbacl4_MergeIgnoreReject(
754         enum smbacl4_acedup_enum acedup,
755         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         SMB4ACL_T *theacl,
789         uid_t ownerUID,
790         gid_t ownerGID
791 )
792 {
793         SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
794         SMB_ACE4_INT_T *aceint;
795
796         for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
797                 SMB_ACE4PROP_T *ace = &aceint->prop;
798
799                 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
800                           "mask: %x, who: %d\n",
801                           ace->aceType, ace->flags, ace->aceFlags,
802                           ace->aceMask, ace->who.id));
803
804                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
805                     !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
806                     ace->who.uid == ownerUID) {
807                         ace->flags |= SMB_ACE4_ID_SPECIAL;
808                         ace->who.special_id = SMB_ACE4_WHO_OWNER;
809                         DEBUG(10,("replaced with special owner ace\n"));
810                 }
811
812                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
813                     ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
814                     ace->who.uid == ownerGID) {
815                         ace->flags |= SMB_ACE4_ID_SPECIAL;
816                         ace->who.special_id = SMB_ACE4_WHO_GROUP;
817                         DEBUG(10,("replaced with special group ace\n"));
818                 }
819         }
820         return True; /* OK */
821 }
822
823 static int smbacl4_substitute_simple(
824         SMB4ACL_T *theacl,
825         uid_t ownerUID,
826         gid_t ownerGID
827 )
828 {
829         SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
830         SMB_ACE4_INT_T *aceint;
831
832         for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
833                 SMB_ACE4PROP_T *ace = &aceint->prop;
834
835                 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
836                           "mask: %x, who: %d\n",
837                           ace->aceType, ace->flags, ace->aceFlags,
838                           ace->aceMask, ace->who.id));
839
840                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
841                     !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
842                     ace->who.uid == ownerUID &&
843                     !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
844                     !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
845                     !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
846                         ace->flags |= SMB_ACE4_ID_SPECIAL;
847                         ace->who.special_id = SMB_ACE4_WHO_OWNER;
848                         DEBUG(10,("replaced with special owner ace\n"));
849                 }
850
851                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
852                     ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
853                     ace->who.uid == ownerGID &&
854                     !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
855                     !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
856                     !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
857                         ace->flags |= SMB_ACE4_ID_SPECIAL;
858                         ace->who.special_id = SMB_ACE4_WHO_GROUP;
859                         DEBUG(10,("replaced with special group ace\n"));
860                 }
861         }
862         return True; /* OK */
863 }
864
865 static SMB4ACL_T *smbacl4_win2nfs4(
866         TALLOC_CTX *mem_ctx,
867         const files_struct *fsp,
868         const struct security_acl *dacl,
869         smbacl4_vfs_params *pparams,
870         uid_t ownerUID,
871         gid_t ownerGID
872 )
873 {
874         SMB4ACL_T *theacl;
875         uint32  i;
876         const char *filename = fsp->fsp_name->base_name;
877
878         DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
879
880         theacl = smb_create_smb4acl(mem_ctx);
881         if (theacl==NULL)
882                 return NULL;
883
884         for(i=0; i<dacl->num_aces; i++) {
885                 SMB_ACE4PROP_T  ace_v4;
886                 bool    addNewACE = True;
887
888                 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
889                                        ownerUID, ownerGID,
890                                        dacl->aces + i, &ace_v4)) {
891                         DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
892                                   filename,
893                                   sid_string_dbg(&((dacl->aces+i)->trustee))));
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         uint32 security_info_sent,
920         const struct security_descriptor *psd,
921         set_nfs4acl_native_fn_t set_nfs4_native)
922 {
923         smbacl4_vfs_params params;
924         SMB4ACL_T *theacl = NULL;
925         bool    result;
926
927         SMB_STRUCT_STAT sbuf;
928         bool set_acl_as_root = false;
929         uid_t newUID = (uid_t)-1;
930         gid_t newGID = (gid_t)-1;
931         int saved_errno;
932         TALLOC_CTX *frame = talloc_stackframe();
933
934         DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
935
936         if ((security_info_sent & (SECINFO_DACL |
937                 SECINFO_GROUP | SECINFO_OWNER)) == 0)
938         {
939                 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
940                         security_info_sent));
941                 TALLOC_FREE(frame);
942                 return NT_STATUS_OK; /* won't show error - later to be
943                                       * refined... */
944         }
945
946         /* Special behaviours */
947         if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME,
948                                    fsp->conn, &params)) {
949                 TALLOC_FREE(frame);
950                 return NT_STATUS_NO_MEMORY;
951         }
952
953         if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
954                 TALLOC_FREE(frame);
955                 return map_nt_error_from_unix(errno);
956         }
957
958         if (params.do_chown) {
959                 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
960                 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
961                                                    security_info_sent, psd);
962                 if (!NT_STATUS_IS_OK(status)) {
963                         DEBUG(8, ("unpack_nt_owners failed"));
964                         TALLOC_FREE(frame);
965                         return status;
966                 }
967                 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
968                     ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
969
970                         status = try_chown(fsp, newUID, newGID);
971                         if (!NT_STATUS_IS_OK(status)) {
972                                 DEBUG(3,("chown %s, %u, %u failed. Error = "
973                                          "%s.\n", fsp_str_dbg(fsp),
974                                          (unsigned int)newUID,
975                                          (unsigned int)newGID,
976                                          nt_errstr(status)));
977                                 TALLOC_FREE(frame);
978                                 return status;
979                         }
980
981                         DEBUG(10,("chown %s, %u, %u succeeded.\n",
982                                   fsp_str_dbg(fsp), (unsigned int)newUID,
983                                   (unsigned int)newGID));
984                         if (smbacl4_GetFileOwner(fsp->conn,
985                                                  fsp->fsp_name->base_name,
986                                                  &sbuf))
987                                 TALLOC_FREE(frame);
988                                 return map_nt_error_from_unix(errno);
989
990                         /* If we successfully chowned, we know we must
991                          * be able to set the acl, so do it as root.
992                          */
993                         set_acl_as_root = true;
994                 }
995         }
996
997         if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
998                 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
999                            security_info_sent));
1000                 TALLOC_FREE(frame);
1001                 return NT_STATUS_OK;
1002         }
1003
1004         theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, &params,
1005                                   sbuf.st_ex_uid, sbuf.st_ex_gid);
1006         if (!theacl) {
1007                 TALLOC_FREE(frame);
1008                 return map_nt_error_from_unix(errno);
1009         }
1010
1011         smbacl4_dump_nfs4acl(10, theacl);
1012
1013         if (set_acl_as_root) {
1014                 become_root();
1015         }
1016         result = set_nfs4_native(handle, fsp, theacl);
1017         saved_errno = errno;
1018         if (set_acl_as_root) {
1019                 unbecome_root();
1020         }
1021
1022         TALLOC_FREE(frame);
1023
1024         if (result!=True) {
1025                 errno = saved_errno;
1026                 DEBUG(10, ("set_nfs4_native failed with %s\n",
1027                            strerror(errno)));
1028                 return map_nt_error_from_unix(errno);
1029         }
1030
1031         DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1032         return NT_STATUS_OK;
1033 }