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