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