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