2 * Convert NFSv4 acls stored per http://www.suse.de/~agruen/nfs4acl/ to NT acls and vice versa.
4 * Copyright (C) Jiri Sasek, 2007
5 * based on the foobar.c module which is copyrighted by Volker Lendecke
6 * based on pvfs_acl_nfs4.c Copyright (C) Andrew Tridgell 2006
8 * based on vfs_fake_acls:
9 * Copyright (C) Tim Potter, 1999-2000
10 * Copyright (C) Alexander Bokovoy, 2002
11 * Copyright (C) Andrew Bartlett, 2002,2012
12 * Copyright (C) Ralph Boehme 2017
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <http://www.gnu.org/licenses/>.
30 #include "system/filesys.h"
31 #include "smbd/smbd.h"
32 #include "nfs4_acls.h"
33 #include "librpc/gen_ndr/ndr_nfs4acl.h"
34 #include "nfs4acl_xattr.h"
35 #include "nfs4acl_xattr_ndr.h"
38 #define DBGC_CLASS DBGC_VFS
40 static struct nfs4acl
*nfs4acl_blob2acl(DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
)
42 enum ndr_err_code ndr_err
;
43 struct nfs4acl
*acl
= talloc_zero(mem_ctx
, struct nfs4acl
);
50 ndr_err
= ndr_pull_struct_blob(blob
, acl
, acl
,
51 (ndr_pull_flags_fn_t
)ndr_pull_nfs4acl
);
53 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
54 DBG_ERR("ndr_pull_acl_t failed: %s\n", ndr_errstr(ndr_err
));
61 static DATA_BLOB
nfs4acl_acl2blob(TALLOC_CTX
*mem_ctx
, struct nfs4acl
*acl
)
63 enum ndr_err_code ndr_err
;
66 ndr_err
= ndr_push_struct_blob(&blob
, mem_ctx
, acl
,
67 (ndr_push_flags_fn_t
)ndr_push_nfs4acl
);
69 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
70 DBG_ERR("ndr_push_acl_t failed: %s\n", ndr_errstr(ndr_err
));
71 return data_blob_null
;
76 static uint16_t nfs4acl_to_smb4acl_flags(uint8_t nfs4acl_flags
)
78 uint16_t smb4acl_flags
= SEC_DESC_SELF_RELATIVE
;
80 if (nfs4acl_flags
& ACL4_AUTO_INHERIT
) {
81 smb4acl_flags
|= SEC_DESC_DACL_AUTO_INHERITED
;
83 if (nfs4acl_flags
& ACL4_PROTECTED
) {
84 smb4acl_flags
|= SEC_DESC_DACL_PROTECTED
;
86 if (nfs4acl_flags
& ACL4_DEFAULTED
) {
87 smb4acl_flags
|= SEC_DESC_DACL_DEFAULTED
;
93 NTSTATUS
nfs4acl_ndr_blob_to_smb4(struct vfs_handle_struct
*handle
,
96 struct SMB4ACL_T
**_smb4acl
)
98 struct nfs4acl
*nfs4acl
= NULL
;
99 struct SMB4ACL_T
*smb4acl
= NULL
;
100 TALLOC_CTX
*frame
= talloc_stackframe();
101 struct nfs4acl_config
*config
= NULL
;
104 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
105 struct nfs4acl_config
,
106 return NT_STATUS_INTERNAL_ERROR
);
108 nfs4acl
= nfs4acl_blob2acl(blob
, frame
);
109 if (nfs4acl
== NULL
) {
111 return NT_STATUS_INTERNAL_ERROR
;
114 smb4acl
= smb_create_smb4acl(mem_ctx
);
115 if (smb4acl
== NULL
) {
117 return NT_STATUS_NO_MEMORY
;
120 if (config
->nfs_version
> ACL4_XATTR_VERSION_40
&&
121 nfs4acl
->a_version
> ACL4_XATTR_VERSION_40
)
123 uint16_t smb4acl_flags
;
125 smb4acl_flags
= nfs4acl_to_smb4acl_flags(nfs4acl
->a_flags
);
126 smbacl4_set_controlflags(smb4acl
, smb4acl_flags
);
129 for (i
= 0; i
< nfs4acl
->a_count
; i
++) {
130 SMB_ACE4PROP_T aceprop
;
132 aceprop
.aceType
= (uint32_t) nfs4acl
->ace
[i
].e_type
;
133 aceprop
.aceFlags
= (uint32_t) nfs4acl
->ace
[i
].e_flags
;
134 aceprop
.aceMask
= (uint32_t) nfs4acl
->ace
[i
].e_mask
;
135 aceprop
.who
.id
= (uint32_t) nfs4acl
->ace
[i
].e_id
;
137 if (!strcmp(nfs4acl
->ace
[i
].e_who
,
138 NFS4ACL_XATTR_OWNER_WHO
)) {
139 aceprop
.flags
= SMB_ACE4_ID_SPECIAL
;
140 aceprop
.who
.special_id
= SMB_ACE4_WHO_OWNER
;
141 } else if (!strcmp(nfs4acl
->ace
[i
].e_who
,
142 NFS4ACL_XATTR_GROUP_WHO
)) {
143 aceprop
.flags
= SMB_ACE4_ID_SPECIAL
;
144 aceprop
.who
.special_id
= SMB_ACE4_WHO_GROUP
;
145 } else if (!strcmp(nfs4acl
->ace
[i
].e_who
,
146 NFS4ACL_XATTR_EVERYONE_WHO
)) {
147 aceprop
.flags
= SMB_ACE4_ID_SPECIAL
;
148 aceprop
.who
.special_id
= SMB_ACE4_WHO_EVERYONE
;
153 if (smb_add_ace4(smb4acl
, &aceprop
) == NULL
) {
155 return NT_STATUS_NO_MEMORY
;
164 static uint8_t smb4acl_to_nfs4acl_flags(uint16_t smb4acl_flags
)
168 if (smb4acl_flags
& SEC_DESC_DACL_AUTO_INHERITED
) {
169 flags
|= ACL4_AUTO_INHERIT
;
171 if (smb4acl_flags
& SEC_DESC_DACL_PROTECTED
) {
172 flags
|= ACL4_PROTECTED
;
174 if (smb4acl_flags
& SEC_DESC_DACL_DEFAULTED
) {
175 flags
|= ACL4_DEFAULTED
;
181 static bool nfs4acl_smb4acl2nfs4acl(vfs_handle_struct
*handle
,
183 struct SMB4ACL_T
*smbacl
,
184 struct nfs4acl
**_nfs4acl
,
185 bool denymissingspecial
)
187 struct nfs4acl_config
*config
= NULL
;
188 struct nfs4acl
*nfs4acl
= NULL
;
189 struct SMB4ACE_T
*smbace
= NULL
;
190 bool have_special_id
= false;
193 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
194 struct nfs4acl_config
,
197 nfs4acl
= talloc_zero(mem_ctx
, struct nfs4acl
);
198 if (nfs4acl
== NULL
) {
203 nfs4acl
->a_count
= smb_get_naces(smbacl
);
205 nfs4acl
->ace
= talloc_zero_array(nfs4acl
, struct nfs4ace
,
207 if (nfs4acl
->ace
== NULL
) {
208 TALLOC_FREE(nfs4acl
);
213 nfs4acl
->a_version
= config
->nfs_version
;
214 if (nfs4acl
->a_version
> ACL4_XATTR_VERSION_40
) {
215 uint16_t smb4acl_flags
;
218 smb4acl_flags
= smbacl4_get_controlflags(smbacl
);
219 flags
= smb4acl_to_nfs4acl_flags(smb4acl_flags
);
220 nfs4acl
->a_flags
= flags
;
223 for (smbace
= smb_first_ace4(smbacl
), i
= 0;
225 smbace
= smb_next_ace4(smbace
), i
++)
227 SMB_ACE4PROP_T
*aceprop
= smb_get_ace4(smbace
);
229 nfs4acl
->ace
[i
].e_type
= aceprop
->aceType
;
230 nfs4acl
->ace
[i
].e_flags
= aceprop
->aceFlags
;
231 nfs4acl
->ace
[i
].e_mask
= aceprop
->aceMask
;
232 nfs4acl
->ace
[i
].e_id
= aceprop
->who
.id
;
233 if(aceprop
->flags
& SMB_ACE4_ID_SPECIAL
) {
234 switch(aceprop
->who
.special_id
) {
235 case SMB_ACE4_WHO_EVERYONE
:
236 nfs4acl
->ace
[i
].e_who
=
237 NFS4ACL_XATTR_EVERYONE_WHO
;
239 case SMB_ACE4_WHO_OWNER
:
240 nfs4acl
->ace
[i
].e_who
=
241 NFS4ACL_XATTR_OWNER_WHO
;
243 case SMB_ACE4_WHO_GROUP
:
244 nfs4acl
->ace
[i
].e_who
=
245 NFS4ACL_XATTR_GROUP_WHO
;
248 DBG_DEBUG("unsupported special_id %d\n",
249 aceprop
->who
.special_id
);
250 continue; /* don't add it !!! */
252 have_special_id
= true;
254 nfs4acl
->ace
[i
].e_who
= "";
258 if (!have_special_id
&& denymissingspecial
) {
259 TALLOC_FREE(nfs4acl
);
264 SMB_ASSERT(i
== nfs4acl
->a_count
);
270 NTSTATUS
nfs4acl_smb4acl_to_ndr_blob(vfs_handle_struct
*handle
,
272 struct SMB4ACL_T
*smb4acl
,
275 struct nfs4acl
*nfs4acl
= NULL
;
277 bool denymissingspecial
;
280 denymissingspecial
= lp_parm_bool(SNUM(handle
->conn
),
282 "denymissingspecial", false);
284 ok
= nfs4acl_smb4acl2nfs4acl(handle
, talloc_tos(), smb4acl
, &nfs4acl
,
287 DBG_ERR("Failed to convert smb ACL to nfs4 ACL.\n");
288 return NT_STATUS_INTERNAL_ERROR
;
291 blob
= nfs4acl_acl2blob(mem_ctx
, nfs4acl
);
292 TALLOC_FREE(nfs4acl
);
293 if (blob
.data
== NULL
) {
294 DBG_ERR("Failed to convert ACL to linear blob for xattr\n");
295 return NT_STATUS_INTERNAL_ERROR
;