s3:libsmb: allow store_cldap_reply() to work with a ipv6 response
[samba.git] / source3 / modules / nfs4acl_xattr_ndr.c
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 static struct nfs4acl *nfs4acl_blob2acl(DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
41 {
42         enum ndr_err_code ndr_err;
43         struct nfs4acl *acl = talloc_zero(mem_ctx, struct nfs4acl);
44
45         if (acl == NULL) {
46                 errno = ENOMEM;
47                 return NULL;
48         }
49
50         ndr_err = ndr_pull_struct_blob(blob, acl, acl,
51                 (ndr_pull_flags_fn_t)ndr_pull_nfs4acl);
52
53         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
54                 DBG_ERR("ndr_pull_acl_t failed: %s\n", ndr_errstr(ndr_err));
55                 TALLOC_FREE(acl);
56                 return NULL;
57         }
58         return acl;
59 }
60
61 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         ndr_err = ndr_push_struct_blob(&blob, mem_ctx, acl,
67                 (ndr_push_flags_fn_t)ndr_push_nfs4acl);
68
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;
72         }
73         return blob;
74 }
75
76 static uint16_t nfs4acl_to_smb4acl_flags(uint8_t nfs4acl_flags)
77 {
78         uint16_t smb4acl_flags = SEC_DESC_SELF_RELATIVE;
79
80         if (nfs4acl_flags & ACL4_AUTO_INHERIT) {
81                 smb4acl_flags |= SEC_DESC_DACL_AUTO_INHERITED;
82         }
83         if (nfs4acl_flags & ACL4_PROTECTED) {
84                 smb4acl_flags |= SEC_DESC_DACL_PROTECTED;
85         }
86         if (nfs4acl_flags & ACL4_DEFAULTED) {
87                 smb4acl_flags |= SEC_DESC_DACL_DEFAULTED;
88         }
89
90         return smb4acl_flags;
91 }
92
93 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         struct nfs4acl *nfs4acl = NULL;
99         struct SMB4ACL_T *smb4acl = NULL;
100         TALLOC_CTX *frame = talloc_stackframe();
101         struct nfs4acl_config *config = NULL;
102         int i;
103
104         SMB_VFS_HANDLE_GET_DATA(handle, config,
105                                 struct nfs4acl_config,
106                                 return NT_STATUS_INTERNAL_ERROR);
107
108         nfs4acl = nfs4acl_blob2acl(blob, frame);
109         if (nfs4acl == NULL) {
110                 TALLOC_FREE(frame);
111                 return NT_STATUS_INTERNAL_ERROR;
112         }
113
114         smb4acl = smb_create_smb4acl(mem_ctx);
115         if (smb4acl == NULL) {
116                 TALLOC_FREE(frame);
117                 return NT_STATUS_NO_MEMORY;
118         }
119
120         if (config->nfs_version > ACL4_XATTR_VERSION_40 &&
121             nfs4acl->a_version > ACL4_XATTR_VERSION_40)
122         {
123                 uint16_t smb4acl_flags;
124
125                 smb4acl_flags = nfs4acl_to_smb4acl_flags(nfs4acl->a_flags);
126                 smbacl4_set_controlflags(smb4acl, smb4acl_flags);
127         }
128
129         for (i = 0; i < nfs4acl->a_count; i++) {
130                 SMB_ACE4PROP_T aceprop;
131
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;
136
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;
149                 } else {
150                         aceprop.flags = 0;
151                 }
152
153                 if (smb_add_ace4(smb4acl, &aceprop) == NULL) {
154                         TALLOC_FREE(frame);
155                         return NT_STATUS_NO_MEMORY;
156                 }
157         }
158
159         *_smb4acl = smb4acl;
160         TALLOC_FREE(frame);
161         return NT_STATUS_OK;
162 }
163
164 static uint8_t smb4acl_to_nfs4acl_flags(uint16_t smb4acl_flags)
165 {
166         uint8_t flags = 0;
167
168         if (smb4acl_flags & SEC_DESC_DACL_AUTO_INHERITED) {
169                 flags |= ACL4_AUTO_INHERIT;
170         }
171         if (smb4acl_flags & SEC_DESC_DACL_PROTECTED) {
172                 flags |= ACL4_PROTECTED;
173         }
174         if (smb4acl_flags & SEC_DESC_DACL_DEFAULTED) {
175                 flags |= ACL4_DEFAULTED;
176         }
177
178         return flags;
179 }
180
181 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         struct nfs4acl_config *config = NULL;
188         struct nfs4acl *nfs4acl = NULL;
189         struct SMB4ACE_T *smbace = NULL;
190         bool have_special_id = false;
191         int i;
192
193         SMB_VFS_HANDLE_GET_DATA(handle, config,
194                                 struct nfs4acl_config,
195                                 return false);
196
197         nfs4acl = talloc_zero(mem_ctx, struct nfs4acl);
198         if (nfs4acl == NULL) {
199                 errno = ENOMEM;
200                 return false;
201         }
202
203         nfs4acl->a_count = smb_get_naces(smbacl);
204
205         nfs4acl->ace = talloc_zero_array(nfs4acl, struct nfs4ace,
206                                          nfs4acl->a_count);
207         if (nfs4acl->ace == NULL) {
208                 TALLOC_FREE(nfs4acl);
209                 errno = ENOMEM;
210                 return false;
211         }
212
213         nfs4acl->a_version = config->nfs_version;
214         if (nfs4acl->a_version > ACL4_XATTR_VERSION_40) {
215                 uint16_t smb4acl_flags;
216                 uint8_t flags;
217
218                 smb4acl_flags = smbacl4_get_controlflags(smbacl);
219                 flags = smb4acl_to_nfs4acl_flags(smb4acl_flags);
220                 nfs4acl->a_flags = flags;
221         }
222
223         for (smbace = smb_first_ace4(smbacl), i = 0;
224              smbace != NULL;
225              smbace = smb_next_ace4(smbace), i++)
226         {
227                 SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
228
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;
238                                 break;
239                         case SMB_ACE4_WHO_OWNER:
240                                 nfs4acl->ace[i].e_who =
241                                         NFS4ACL_XATTR_OWNER_WHO;
242                                 break;
243                         case SMB_ACE4_WHO_GROUP:
244                                 nfs4acl->ace[i].e_who =
245                                         NFS4ACL_XATTR_GROUP_WHO;
246                                 break;
247                         default:
248                                 DBG_DEBUG("unsupported special_id %d\n",
249                                           aceprop->who.special_id);
250                                 continue; /* don't add it !!! */
251                         }
252                         have_special_id = true;
253                 } else {
254                         nfs4acl->ace[i].e_who = "";
255                 }
256         }
257
258         if (!have_special_id && denymissingspecial) {
259                 TALLOC_FREE(nfs4acl);
260                 errno = EACCES;
261                 return false;
262         }
263
264         SMB_ASSERT(i == nfs4acl->a_count);
265
266         *_nfs4acl = nfs4acl;
267         return true;
268 }
269
270 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         struct nfs4acl *nfs4acl = NULL;
276         DATA_BLOB blob;
277         bool denymissingspecial;
278         bool ok;
279
280         denymissingspecial = lp_parm_bool(SNUM(handle->conn),
281                                           "nfs4acl_xattr",
282                                           "denymissingspecial", false);
283
284         ok = nfs4acl_smb4acl2nfs4acl(handle, talloc_tos(), smb4acl, &nfs4acl,
285                                      denymissingspecial);
286         if (!ok) {
287                 DBG_ERR("Failed to convert smb ACL to nfs4 ACL.\n");
288                 return NT_STATUS_INTERNAL_ERROR;
289         }
290
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;
296         }
297
298         *_blob = blob;
299         return NT_STATUS_OK;
300 }