vfs_nfs4acl_xattr: move the meat of the implementation to a seperate file
[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 NTSTATUS nfs4acl_ndr_blob_to_smb4(struct vfs_handle_struct *handle,
77                                   TALLOC_CTX *mem_ctx,
78                                   DATA_BLOB *blob,
79                                   struct SMB4ACL_T **_smb4acl)
80 {
81         struct nfs4acl *nfs4acl = NULL;
82         struct SMB4ACL_T *smb4acl = NULL;
83         TALLOC_CTX *frame = talloc_stackframe();
84         struct nfs4acl_config *config = NULL;
85         int i;
86
87         SMB_VFS_HANDLE_GET_DATA(handle, config,
88                                 struct nfs4acl_config,
89                                 return NT_STATUS_INTERNAL_ERROR);
90
91         nfs4acl = nfs4acl_blob2acl(blob, frame);
92         if (nfs4acl == NULL) {
93                 TALLOC_FREE(frame);
94                 return NT_STATUS_INTERNAL_ERROR;
95         }
96
97         smb4acl = smb_create_smb4acl(mem_ctx);
98         if (smb4acl == NULL) {
99                 TALLOC_FREE(frame);
100                 return NT_STATUS_NO_MEMORY;
101         }
102
103         for (i = 0; i < nfs4acl->a_count; i++) {
104                 SMB_ACE4PROP_T aceprop;
105
106                 aceprop.aceType  = (uint32_t) nfs4acl->ace[i].e_type;
107                 aceprop.aceFlags = (uint32_t) nfs4acl->ace[i].e_flags;
108                 aceprop.aceMask  = (uint32_t) nfs4acl->ace[i].e_mask;
109                 aceprop.who.id   = (uint32_t) nfs4acl->ace[i].e_id;
110
111                 if (!strcmp(nfs4acl->ace[i].e_who,
112                             NFS4ACL_XATTR_OWNER_WHO)) {
113                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
114                         aceprop.who.special_id = SMB_ACE4_WHO_OWNER;
115                 } else if (!strcmp(nfs4acl->ace[i].e_who,
116                                    NFS4ACL_XATTR_GROUP_WHO)) {
117                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
118                         aceprop.who.special_id = SMB_ACE4_WHO_GROUP;
119                 } else if (!strcmp(nfs4acl->ace[i].e_who,
120                                    NFS4ACL_XATTR_EVERYONE_WHO)) {
121                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
122                         aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE;
123                 } else {
124                         aceprop.flags = 0;
125                 }
126
127                 if (smb_add_ace4(smb4acl, &aceprop) == NULL) {
128                         TALLOC_FREE(frame);
129                         return NT_STATUS_NO_MEMORY;
130                 }
131         }
132
133         *_smb4acl = smb4acl;
134         TALLOC_FREE(frame);
135         return NT_STATUS_OK;
136 }
137
138 static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
139                                     struct SMB4ACL_T *smbacl,
140                                     struct nfs4acl **_nfs4acl,
141                                     bool denymissingspecial)
142 {
143         struct nfs4acl *nfs4acl = NULL;
144         struct SMB4ACE_T *smbace = NULL;
145         bool have_special_id = false;
146         int i;
147
148         nfs4acl = talloc_zero(mem_ctx, struct nfs4acl);
149         if (nfs4acl == NULL) {
150                 errno = ENOMEM;
151                 return false;
152         }
153
154         nfs4acl->a_count = smb_get_naces(smbacl);
155
156         nfs4acl->ace = talloc_zero_array(nfs4acl, struct nfs4ace,
157                                          nfs4acl->a_count);
158         if (nfs4acl->ace == NULL) {
159                 TALLOC_FREE(nfs4acl);
160                 errno = ENOMEM;
161                 return false;
162         }
163
164         for (smbace = smb_first_ace4(smbacl), i = 0;
165              smbace != NULL;
166              smbace = smb_next_ace4(smbace), i++)
167         {
168                 SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
169
170                 nfs4acl->ace[i].e_type        = aceprop->aceType;
171                 nfs4acl->ace[i].e_flags       = aceprop->aceFlags;
172                 nfs4acl->ace[i].e_mask        = aceprop->aceMask;
173                 nfs4acl->ace[i].e_id          = aceprop->who.id;
174                 if(aceprop->flags & SMB_ACE4_ID_SPECIAL) {
175                         switch(aceprop->who.special_id) {
176                         case SMB_ACE4_WHO_EVERYONE:
177                                 nfs4acl->ace[i].e_who =
178                                         NFS4ACL_XATTR_EVERYONE_WHO;
179                                 break;
180                         case SMB_ACE4_WHO_OWNER:
181                                 nfs4acl->ace[i].e_who =
182                                         NFS4ACL_XATTR_OWNER_WHO;
183                                 break;
184                         case SMB_ACE4_WHO_GROUP:
185                                 nfs4acl->ace[i].e_who =
186                                         NFS4ACL_XATTR_GROUP_WHO;
187                                 break;
188                         default:
189                                 DBG_DEBUG("unsupported special_id %d\n",
190                                           aceprop->who.special_id);
191                                 continue; /* don't add it !!! */
192                         }
193                         have_special_id = true;
194                 } else {
195                         nfs4acl->ace[i].e_who = "";
196                 }
197         }
198
199         if (!have_special_id && denymissingspecial) {
200                 TALLOC_FREE(nfs4acl);
201                 errno = EACCES;
202                 return false;
203         }
204
205         SMB_ASSERT(i == nfs4acl->a_count);
206
207         *_nfs4acl = nfs4acl;
208         return true;
209 }
210
211 NTSTATUS nfs4acl_smb4acl_to_ndr_blob(vfs_handle_struct *handle,
212                                      TALLOC_CTX *mem_ctx,
213                                      struct SMB4ACL_T *smb4acl,
214                                      DATA_BLOB *_blob)
215 {
216         struct nfs4acl *nfs4acl = NULL;
217         DATA_BLOB blob;
218         bool denymissingspecial;
219         bool ok;
220
221         denymissingspecial = lp_parm_bool(SNUM(handle->conn),
222                                           "nfs4acl_xattr",
223                                           "denymissingspecial", false);
224
225         ok = nfs4acl_smb4acl2nfs4acl(talloc_tos(), smb4acl, &nfs4acl,
226                                      denymissingspecial);
227         if (!ok) {
228                 DBG_ERR("Failed to convert smb ACL to nfs4 ACL.\n");
229                 return NT_STATUS_INTERNAL_ERROR;
230         }
231
232         blob = nfs4acl_acl2blob(mem_ctx, nfs4acl);
233         TALLOC_FREE(nfs4acl);
234         if (blob.data == NULL) {
235                 DBG_ERR("Failed to convert ACL to linear blob for xattr\n");
236                 return NT_STATUS_INTERNAL_ERROR;
237         }
238
239         *_blob = blob;
240         return NT_STATUS_OK;
241 }