vfs: Support NFS control flags in nfs4_acls.c.
[samba.git] / source3 / modules / nfs4_acls.c
1 /*
2  * NFS4 ACL handling
3  *
4  * Copyright (C) Jim McDonough, 2006
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "smbd/smbd.h"
22 #include "nfs4_acls.h"
23 #include "librpc/gen_ndr/ndr_security.h"
24 #include "../libcli/security/dom_sid.h"
25 #include "../libcli/security/security.h"
26 #include "dbwrap/dbwrap.h"
27 #include "dbwrap/dbwrap_open.h"
28 #include "system/filesys.h"
29 #include "passdb/lookup_sid.h"
30 #include "util_tdb.h"
31 #include "lib/param/loadparm.h"
32
33 #undef DBGC_CLASS
34 #define DBGC_CLASS DBGC_ACLS
35
36 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
37
38 extern const struct generic_mapping file_generic_mapping;
39
40 #define SMB_ACE4_INT_MAGIC 0x76F8A967
41 typedef struct _SMB_ACE4_INT_T
42 {
43         uint32  magic;
44         SMB_ACE4PROP_T  prop;
45         void    *next;
46 } SMB_ACE4_INT_T;
47
48 #define SMB_ACL4_INT_MAGIC 0x29A3E792
49 typedef struct _SMB_ACL4_INT_T
50 {
51         uint32  magic;
52         uint16_t controlflags;
53         uint32  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         memset(params, 0, sizeof(smbacl4_vfs_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(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(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 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 (SMB4ACL_T *)theacl;
225 }
226
227 SMB4ACE_T *smb_add_ace4(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 (SMB4ACE_T *)ace;
255 }
256
257 SMB_ACE4PROP_T *smb_get_ace4(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 SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace)
267 {
268         SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
269         if (aceint==NULL)
270                 return NULL;
271
272         return (SMB4ACE_T *)aceint->next;
273 }
274
275 SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl)
276 {
277         SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
278         if (aclint==NULL)
279                 return NULL;
280
281         return (SMB4ACE_T *)aclint->first;
282 }
283
284 uint32 smb_get_naces(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(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(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         memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
317
318         /* Get the stat struct for the owner info. */
319         if (vfs_stat_smb_fname(conn, filename, psbuf) != 0)
320         {
321                 DEBUG(8, ("vfs_stat_smb_fname 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         memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
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         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, ("smbacl_nfs42win entered\n"));
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 security_info,
529                                            TALLOC_CTX *mem_ctx,
530                                            struct security_descriptor **ppdesc,
531                                            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 security_info,
587                               TALLOC_CTX *mem_ctx,
588                               struct security_descriptor **ppdesc,
589                               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 security_info,
612                              TALLOC_CTX *mem_ctx,
613                              struct security_descriptor **ppdesc,
614                              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, 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         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         memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
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 {
782                         DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
783                                   "convert %s to uid or gid\n",
784                                   filename->base_name,
785                                   sid_string_dbg(&ace_nt->trustee)));
786                         return false;
787                 }
788         }
789
790         return true; /* OK */
791 }
792
793 static int smbacl4_MergeIgnoreReject(
794         enum smbacl4_acedup_enum acedup,
795         SMB4ACL_T *theacl, /* may modify it */
796         SMB_ACE4PROP_T *ace, /* the "new" ACE */
797         bool    *paddNewACE,
798         int     i
799 )
800 {
801         int     result = 0;
802         SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
803         if (ace4found)
804         {
805                 switch(acedup)
806                 {
807                 case e_merge: /* "merge" flags */
808                         *paddNewACE = false;
809                         ace4found->aceFlags |= ace->aceFlags;
810                         ace4found->aceMask |= ace->aceMask;
811                         break;
812                 case e_ignore: /* leave out this record */
813                         *paddNewACE = false;
814                         break;
815                 case e_reject: /* do an error */
816                         DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
817                         errno = EINVAL; /* SHOULD be set on any _real_ error */
818                         result = -1;
819                         break;
820                 default:
821                         break;
822                 }
823         }
824         return result;
825 }
826
827 static int smbacl4_substitute_special(
828         SMB4ACL_T *theacl,
829         uid_t ownerUID,
830         gid_t ownerGID
831 )
832 {
833         SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
834         SMB_ACE4_INT_T *aceint;
835
836         for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
837                 SMB_ACE4PROP_T *ace = &aceint->prop;
838
839                 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
840                           "mask: %x, who: %d\n",
841                           ace->aceType, ace->flags, ace->aceFlags,
842                           ace->aceMask, ace->who.id));
843
844                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
845                     !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
846                     ace->who.uid == ownerUID) {
847                         ace->flags |= SMB_ACE4_ID_SPECIAL;
848                         ace->who.special_id = SMB_ACE4_WHO_OWNER;
849                         DEBUG(10,("replaced with special owner ace\n"));
850                 }
851
852                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
853                     ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
854                     ace->who.uid == ownerGID) {
855                         ace->flags |= SMB_ACE4_ID_SPECIAL;
856                         ace->who.special_id = SMB_ACE4_WHO_GROUP;
857                         DEBUG(10,("replaced with special group ace\n"));
858                 }
859         }
860         return true; /* OK */
861 }
862
863 static int smbacl4_substitute_simple(
864         SMB4ACL_T *theacl,
865         uid_t ownerUID,
866         gid_t ownerGID
867 )
868 {
869         SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
870         SMB_ACE4_INT_T *aceint;
871
872         for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
873                 SMB_ACE4PROP_T *ace = &aceint->prop;
874
875                 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
876                           "mask: %x, who: %d\n",
877                           ace->aceType, ace->flags, ace->aceFlags,
878                           ace->aceMask, ace->who.id));
879
880                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
881                     !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
882                     ace->who.uid == ownerUID &&
883                     !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
884                     !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
885                     !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
886                         ace->flags |= SMB_ACE4_ID_SPECIAL;
887                         ace->who.special_id = SMB_ACE4_WHO_OWNER;
888                         DEBUG(10,("replaced with special owner ace\n"));
889                 }
890
891                 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
892                     ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
893                     ace->who.uid == ownerGID &&
894                     !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
895                     !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
896                     !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
897                         ace->flags |= SMB_ACE4_ID_SPECIAL;
898                         ace->who.special_id = SMB_ACE4_WHO_GROUP;
899                         DEBUG(10,("replaced with special group ace\n"));
900                 }
901         }
902         return true; /* OK */
903 }
904
905 static SMB4ACL_T *smbacl4_win2nfs4(
906         TALLOC_CTX *mem_ctx,
907         const files_struct *fsp,
908         const struct security_acl *dacl,
909         smbacl4_vfs_params *pparams,
910         uid_t ownerUID,
911         gid_t ownerGID
912 )
913 {
914         SMB4ACL_T *theacl;
915         uint32  i;
916         const char *filename = fsp->fsp_name->base_name;
917
918         DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
919
920         theacl = smb_create_smb4acl(mem_ctx);
921         if (theacl==NULL)
922                 return NULL;
923
924         for(i=0; i<dacl->num_aces; i++) {
925                 SMB_ACE4PROP_T  ace_v4;
926                 bool    addNewACE = true;
927
928                 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
929                                        ownerUID, ownerGID,
930                                        dacl->aces + i, &ace_v4)) {
931                         DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
932                                   filename,
933                                   sid_string_dbg(&((dacl->aces+i)->trustee))));
934                         continue;
935                 }
936
937                 if (pparams->acedup!=e_dontcare) {
938                         if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
939                                 &ace_v4, &addNewACE, i))
940                                 return NULL;
941                 }
942
943                 if (addNewACE)
944                         smb_add_ace4(theacl, &ace_v4);
945         }
946
947         if (pparams->mode==e_simple) {
948                 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
949         }
950
951         if (pparams->mode==e_special) {
952                 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
953         }
954
955         return theacl;
956 }
957
958 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
959         uint32 security_info_sent,
960         const struct security_descriptor *psd,
961         set_nfs4acl_native_fn_t set_nfs4_native)
962 {
963         smbacl4_vfs_params params;
964         SMB4ACL_T *theacl = NULL;
965         bool    result;
966
967         SMB_STRUCT_STAT sbuf;
968         bool set_acl_as_root = false;
969         uid_t newUID = (uid_t)-1;
970         gid_t newGID = (gid_t)-1;
971         int saved_errno;
972         TALLOC_CTX *frame = talloc_stackframe();
973
974         DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
975
976         if ((security_info_sent & (SECINFO_DACL |
977                 SECINFO_GROUP | SECINFO_OWNER)) == 0)
978         {
979                 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
980                         security_info_sent));
981                 TALLOC_FREE(frame);
982                 return NT_STATUS_OK; /* won't show error - later to be
983                                       * refined... */
984         }
985
986         /* Special behaviours */
987         if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME,
988                                    fsp->conn, &params)) {
989                 TALLOC_FREE(frame);
990                 return NT_STATUS_NO_MEMORY;
991         }
992
993         if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
994                 TALLOC_FREE(frame);
995                 return map_nt_error_from_unix(errno);
996         }
997
998         if (params.do_chown) {
999                 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
1000                 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
1001                                                    security_info_sent, psd);
1002                 if (!NT_STATUS_IS_OK(status)) {
1003                         DEBUG(8, ("unpack_nt_owners failed"));
1004                         TALLOC_FREE(frame);
1005                         return status;
1006                 }
1007                 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
1008                     ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
1009
1010                         status = try_chown(fsp, newUID, newGID);
1011                         if (!NT_STATUS_IS_OK(status)) {
1012                                 DEBUG(3,("chown %s, %u, %u failed. Error = "
1013                                          "%s.\n", fsp_str_dbg(fsp),
1014                                          (unsigned int)newUID,
1015                                          (unsigned int)newGID,
1016                                          nt_errstr(status)));
1017                                 TALLOC_FREE(frame);
1018                                 return status;
1019                         }
1020
1021                         DEBUG(10,("chown %s, %u, %u succeeded.\n",
1022                                   fsp_str_dbg(fsp), (unsigned int)newUID,
1023                                   (unsigned int)newGID));
1024                         if (smbacl4_GetFileOwner(fsp->conn,
1025                                                  fsp->fsp_name->base_name,
1026                                                  &sbuf)){
1027                                 TALLOC_FREE(frame);
1028                                 return map_nt_error_from_unix(errno);
1029                         }
1030
1031                         /* If we successfully chowned, we know we must
1032                          * be able to set the acl, so do it as root.
1033                          */
1034                         set_acl_as_root = true;
1035                 }
1036         }
1037
1038         if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1039                 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1040                            security_info_sent));
1041                 TALLOC_FREE(frame);
1042                 return NT_STATUS_OK;
1043         }
1044
1045         theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, &params,
1046                                   sbuf.st_ex_uid, sbuf.st_ex_gid);
1047         if (!theacl) {
1048                 TALLOC_FREE(frame);
1049                 return map_nt_error_from_unix(errno);
1050         }
1051
1052         smbacl4_set_controlflags(theacl, psd->type);
1053         smbacl4_dump_nfs4acl(10, theacl);
1054
1055         if (set_acl_as_root) {
1056                 become_root();
1057         }
1058         result = set_nfs4_native(handle, fsp, theacl);
1059         saved_errno = errno;
1060         if (set_acl_as_root) {
1061                 unbecome_root();
1062         }
1063
1064         TALLOC_FREE(frame);
1065
1066         if (result!=true) {
1067                 errno = saved_errno;
1068                 DEBUG(10, ("set_nfs4_native failed with %s\n",
1069                            strerror(errno)));
1070                 return map_nt_error_from_unix(errno);
1071         }
1072
1073         DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1074         return NT_STATUS_OK;
1075 }