Line data Source code
1 : /*
2 : * Convert NFSv4 acls stored per http://www.suse.de/~agruen/nfs4acl/ to NT acls and vice versa.
3 : *
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
7 : *
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
13 : *
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.
18 : *
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.
23 : *
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/>.
26 : *
27 : */
28 :
29 : #include "includes.h"
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"
36 :
37 : #undef DBGC_CLASS
38 : #define DBGC_CLASS DBGC_VFS
39 :
40 3756 : static struct nfs4acl *nfs4acl_blob2acl(DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
41 : {
42 : enum ndr_err_code ndr_err;
43 3756 : struct nfs4acl *acl = talloc_zero(mem_ctx, struct nfs4acl);
44 :
45 3756 : if (acl == NULL) {
46 0 : errno = ENOMEM;
47 0 : return NULL;
48 : }
49 :
50 3756 : ndr_err = ndr_pull_struct_blob(blob, acl, acl,
51 : (ndr_pull_flags_fn_t)ndr_pull_nfs4acl);
52 :
53 3756 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
54 0 : DBG_ERR("ndr_pull_acl_t failed: %s\n", ndr_errstr(ndr_err));
55 0 : TALLOC_FREE(acl);
56 0 : return NULL;
57 : }
58 3756 : return acl;
59 : }
60 :
61 2142 : static DATA_BLOB nfs4acl_acl2blob(TALLOC_CTX *mem_ctx, struct nfs4acl *acl)
62 : {
63 : enum ndr_err_code ndr_err;
64 : DATA_BLOB blob;
65 :
66 2142 : ndr_err = ndr_push_struct_blob(&blob, mem_ctx, acl,
67 : (ndr_push_flags_fn_t)ndr_push_nfs4acl);
68 :
69 2142 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
70 0 : DBG_ERR("ndr_push_acl_t failed: %s\n", ndr_errstr(ndr_err));
71 0 : return data_blob_null;
72 : }
73 2142 : return blob;
74 : }
75 :
76 1252 : static uint16_t nfs4acl_to_smb4acl_flags(uint8_t nfs4acl_flags)
77 : {
78 1252 : uint16_t smb4acl_flags = SEC_DESC_SELF_RELATIVE;
79 :
80 1252 : if (nfs4acl_flags & ACL4_AUTO_INHERIT) {
81 148 : smb4acl_flags |= SEC_DESC_DACL_AUTO_INHERITED;
82 : }
83 1252 : if (nfs4acl_flags & ACL4_PROTECTED) {
84 294 : smb4acl_flags |= SEC_DESC_DACL_PROTECTED;
85 : }
86 1252 : if (nfs4acl_flags & ACL4_DEFAULTED) {
87 0 : smb4acl_flags |= SEC_DESC_DACL_DEFAULTED;
88 : }
89 :
90 1252 : return smb4acl_flags;
91 : }
92 :
93 3756 : NTSTATUS nfs4acl_ndr_blob_to_smb4(struct vfs_handle_struct *handle,
94 : TALLOC_CTX *mem_ctx,
95 : DATA_BLOB *blob,
96 : struct SMB4ACL_T **_smb4acl)
97 : {
98 3756 : struct nfs4acl *nfs4acl = NULL;
99 3756 : struct SMB4ACL_T *smb4acl = NULL;
100 3756 : TALLOC_CTX *frame = talloc_stackframe();
101 3756 : struct nfs4acl_config *config = NULL;
102 : int i;
103 :
104 3756 : SMB_VFS_HANDLE_GET_DATA(handle, config,
105 : struct nfs4acl_config,
106 : return NT_STATUS_INTERNAL_ERROR);
107 :
108 3756 : nfs4acl = nfs4acl_blob2acl(blob, frame);
109 3756 : if (nfs4acl == NULL) {
110 0 : TALLOC_FREE(frame);
111 0 : return NT_STATUS_INTERNAL_ERROR;
112 : }
113 :
114 3756 : smb4acl = smb_create_smb4acl(mem_ctx);
115 3756 : if (smb4acl == NULL) {
116 0 : TALLOC_FREE(frame);
117 0 : return NT_STATUS_NO_MEMORY;
118 : }
119 :
120 3756 : if (config->nfs_version > ACL4_XATTR_VERSION_40 &&
121 1252 : nfs4acl->a_version > ACL4_XATTR_VERSION_40)
122 : {
123 : uint16_t smb4acl_flags;
124 :
125 1252 : smb4acl_flags = nfs4acl_to_smb4acl_flags(nfs4acl->a_flags);
126 1252 : smbacl4_set_controlflags(smb4acl, smb4acl_flags);
127 : }
128 :
129 8720 : for (i = 0; i < nfs4acl->a_count; i++) {
130 : SMB_ACE4PROP_T aceprop;
131 :
132 4964 : aceprop.aceType = (uint32_t) nfs4acl->ace[i].e_type;
133 4964 : aceprop.aceFlags = (uint32_t) nfs4acl->ace[i].e_flags;
134 4964 : aceprop.aceMask = (uint32_t) nfs4acl->ace[i].e_mask;
135 4964 : aceprop.who.id = (uint32_t) nfs4acl->ace[i].e_id;
136 :
137 4964 : if (!strcmp(nfs4acl->ace[i].e_who,
138 : NFS4ACL_XATTR_OWNER_WHO)) {
139 2914 : aceprop.flags = SMB_ACE4_ID_SPECIAL;
140 2914 : aceprop.who.special_id = SMB_ACE4_WHO_OWNER;
141 2050 : } else if (!strcmp(nfs4acl->ace[i].e_who,
142 : NFS4ACL_XATTR_GROUP_WHO)) {
143 0 : aceprop.flags = SMB_ACE4_ID_SPECIAL;
144 0 : aceprop.who.special_id = SMB_ACE4_WHO_GROUP;
145 2050 : } else if (!strcmp(nfs4acl->ace[i].e_who,
146 : NFS4ACL_XATTR_EVERYONE_WHO)) {
147 1368 : aceprop.flags = SMB_ACE4_ID_SPECIAL;
148 1368 : aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE;
149 : } else {
150 682 : aceprop.flags = 0;
151 : }
152 :
153 4964 : if (smb_add_ace4(smb4acl, &aceprop) == NULL) {
154 0 : TALLOC_FREE(frame);
155 0 : return NT_STATUS_NO_MEMORY;
156 : }
157 : }
158 :
159 3756 : *_smb4acl = smb4acl;
160 3756 : TALLOC_FREE(frame);
161 3756 : return NT_STATUS_OK;
162 : }
163 :
164 714 : static uint8_t smb4acl_to_nfs4acl_flags(uint16_t smb4acl_flags)
165 : {
166 714 : uint8_t flags = 0;
167 :
168 714 : if (smb4acl_flags & SEC_DESC_DACL_AUTO_INHERITED) {
169 114 : flags |= ACL4_AUTO_INHERIT;
170 : }
171 714 : if (smb4acl_flags & SEC_DESC_DACL_PROTECTED) {
172 238 : flags |= ACL4_PROTECTED;
173 : }
174 714 : if (smb4acl_flags & SEC_DESC_DACL_DEFAULTED) {
175 0 : flags |= ACL4_DEFAULTED;
176 : }
177 :
178 714 : return flags;
179 : }
180 :
181 2142 : static bool nfs4acl_smb4acl2nfs4acl(vfs_handle_struct *handle,
182 : TALLOC_CTX *mem_ctx,
183 : struct SMB4ACL_T *smbacl,
184 : struct nfs4acl **_nfs4acl,
185 : bool denymissingspecial)
186 : {
187 2142 : struct nfs4acl_config *config = NULL;
188 2142 : struct nfs4acl *nfs4acl = NULL;
189 2142 : struct SMB4ACE_T *smbace = NULL;
190 2142 : bool have_special_id = false;
191 : int i;
192 :
193 2142 : SMB_VFS_HANDLE_GET_DATA(handle, config,
194 : struct nfs4acl_config,
195 : return false);
196 :
197 2142 : nfs4acl = talloc_zero(mem_ctx, struct nfs4acl);
198 2142 : if (nfs4acl == NULL) {
199 0 : errno = ENOMEM;
200 0 : return false;
201 : }
202 :
203 2142 : nfs4acl->a_count = smb_get_naces(smbacl);
204 :
205 2142 : nfs4acl->ace = talloc_zero_array(nfs4acl, struct nfs4ace,
206 : nfs4acl->a_count);
207 2142 : if (nfs4acl->ace == NULL) {
208 0 : TALLOC_FREE(nfs4acl);
209 0 : errno = ENOMEM;
210 0 : return false;
211 : }
212 :
213 2142 : nfs4acl->a_version = config->nfs_version;
214 2142 : if (nfs4acl->a_version > ACL4_XATTR_VERSION_40) {
215 : uint16_t smb4acl_flags;
216 : uint8_t flags;
217 :
218 714 : smb4acl_flags = smbacl4_get_controlflags(smbacl);
219 714 : flags = smb4acl_to_nfs4acl_flags(smb4acl_flags);
220 714 : nfs4acl->a_flags = flags;
221 : }
222 :
223 2142 : for (smbace = smb_first_ace4(smbacl), i = 0;
224 4516 : smbace != NULL;
225 2374 : smbace = smb_next_ace4(smbace), i++)
226 : {
227 2374 : SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
228 :
229 2374 : nfs4acl->ace[i].e_type = aceprop->aceType;
230 2374 : nfs4acl->ace[i].e_flags = aceprop->aceFlags;
231 2374 : nfs4acl->ace[i].e_mask = aceprop->aceMask;
232 2374 : nfs4acl->ace[i].e_id = aceprop->who.id;
233 2374 : if(aceprop->flags & SMB_ACE4_ID_SPECIAL) {
234 2222 : switch(aceprop->who.special_id) {
235 282 : case SMB_ACE4_WHO_EVERYONE:
236 282 : nfs4acl->ace[i].e_who =
237 : NFS4ACL_XATTR_EVERYONE_WHO;
238 282 : break;
239 1940 : case SMB_ACE4_WHO_OWNER:
240 1940 : nfs4acl->ace[i].e_who =
241 : NFS4ACL_XATTR_OWNER_WHO;
242 1940 : break;
243 0 : case SMB_ACE4_WHO_GROUP:
244 0 : nfs4acl->ace[i].e_who =
245 : NFS4ACL_XATTR_GROUP_WHO;
246 0 : break;
247 0 : default:
248 0 : DBG_DEBUG("unsupported special_id %d\n",
249 : aceprop->who.special_id);
250 0 : continue; /* don't add it !!! */
251 : }
252 2222 : have_special_id = true;
253 : } else {
254 152 : nfs4acl->ace[i].e_who = "";
255 : }
256 : }
257 :
258 2142 : if (!have_special_id && denymissingspecial) {
259 0 : TALLOC_FREE(nfs4acl);
260 0 : errno = EACCES;
261 0 : return false;
262 : }
263 :
264 2142 : SMB_ASSERT(i == nfs4acl->a_count);
265 :
266 2142 : *_nfs4acl = nfs4acl;
267 2142 : return true;
268 : }
269 :
270 2142 : NTSTATUS nfs4acl_smb4acl_to_ndr_blob(vfs_handle_struct *handle,
271 : TALLOC_CTX *mem_ctx,
272 : struct SMB4ACL_T *smb4acl,
273 : DATA_BLOB *_blob)
274 : {
275 2142 : struct nfs4acl *nfs4acl = NULL;
276 : DATA_BLOB blob;
277 : bool denymissingspecial;
278 : bool ok;
279 :
280 2142 : denymissingspecial = lp_parm_bool(SNUM(handle->conn),
281 : "nfs4acl_xattr",
282 : "denymissingspecial", false);
283 :
284 2142 : ok = nfs4acl_smb4acl2nfs4acl(handle, talloc_tos(), smb4acl, &nfs4acl,
285 : denymissingspecial);
286 2142 : if (!ok) {
287 0 : DBG_ERR("Failed to convert smb ACL to nfs4 ACL.\n");
288 0 : return NT_STATUS_INTERNAL_ERROR;
289 : }
290 :
291 2142 : blob = nfs4acl_acl2blob(mem_ctx, nfs4acl);
292 2142 : TALLOC_FREE(nfs4acl);
293 2142 : if (blob.data == NULL) {
294 0 : DBG_ERR("Failed to convert ACL to linear blob for xattr\n");
295 0 : return NT_STATUS_INTERNAL_ERROR;
296 : }
297 :
298 2142 : *_blob = blob;
299 2142 : return NT_STATUS_OK;
300 : }
|