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