lib: modules: Change XXX_init interface from XXX_init(void) to XXX_init(TALLOC_CTX *)
[samba.git] / source3 / modules / vfs_acl_xattr.c
1 /*
2  * Store Windows ACLs in xattrs.
3  *
4  * Copyright (C) Volker Lendecke, 2008
5  * Copyright (C) Jeremy Allison, 2008
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "includes.h"
22 #include "smbd/smbd.h"
23 #include "librpc/gen_ndr/xattr.h"
24 #include "librpc/gen_ndr/ndr_xattr.h"
25 #include "../lib/crypto/sha256.h"
26 #include "auth.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_VFS
30
31 /* Pull in the common functions. */
32 #define ACL_MODULE_NAME "acl_xattr"
33
34 #include "modules/vfs_acl_common.c"
35
36 /*******************************************************************
37  Pull a security descriptor into a DATA_BLOB from a xattr.
38 *******************************************************************/
39
40 static ssize_t getxattr_do(vfs_handle_struct *handle,
41                            files_struct *fsp,
42                            const struct smb_filename *smb_fname,
43                            const char *xattr_name,
44                            uint8_t *val,
45                            size_t size)
46 {
47         ssize_t sizeret;
48         int saved_errno = 0;
49
50         become_root();
51         if (fsp && fsp->fh->fd != -1) {
52                 sizeret = SMB_VFS_FGETXATTR(fsp, xattr_name, val, size);
53         } else {
54                 sizeret = SMB_VFS_GETXATTR(handle->conn, smb_fname->base_name,
55                                            XATTR_NTACL_NAME, val, size);
56         }
57         if (sizeret == -1) {
58                 saved_errno = errno;
59         }
60         unbecome_root();
61
62         if (saved_errno != 0) {
63                 errno = saved_errno;
64         }
65
66         return sizeret;
67 }
68
69 static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
70                         vfs_handle_struct *handle,
71                         files_struct *fsp,
72                         const struct smb_filename *smb_fname,
73                         DATA_BLOB *pblob)
74 {
75         size_t size = 4096;
76         uint8_t *val = NULL;
77         uint8_t *tmp;
78         ssize_t sizeret;
79
80         ZERO_STRUCTP(pblob);
81
82   again:
83
84         tmp = talloc_realloc(ctx, val, uint8_t, size);
85         if (tmp == NULL) {
86                 TALLOC_FREE(val);
87                 return NT_STATUS_NO_MEMORY;
88         }
89         val = tmp;
90
91         sizeret =
92             getxattr_do(handle, fsp, smb_fname, XATTR_NTACL_NAME, val, size);
93
94         if (sizeret >= 0) {
95                 pblob->data = val;
96                 pblob->length = sizeret;
97                 return NT_STATUS_OK;
98         }
99
100         if (errno != ERANGE) {
101                 goto err;
102         }
103
104         /* Too small, try again. */
105         sizeret =
106             getxattr_do(handle, fsp, smb_fname, XATTR_NTACL_NAME, NULL, 0);
107         if (sizeret < 0) {
108                 goto err;
109         }
110
111         if (size < sizeret) {
112                 size = sizeret;
113         }
114
115         if (size > 65536) {
116                 /* Max ACL size is 65536 bytes. */
117                 errno = ERANGE;
118                 goto err;
119         }
120
121         goto again;
122   err:
123         /* Real error - exit here. */
124         TALLOC_FREE(val);
125         return map_nt_error_from_unix(errno);
126 }
127
128 /*******************************************************************
129  Store a DATA_BLOB into an xattr given an fsp pointer.
130 *******************************************************************/
131
132 static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
133                                 files_struct *fsp,
134                                 DATA_BLOB *pblob)
135 {
136         int ret;
137         int saved_errno = 0;
138
139         DEBUG(10,("store_acl_blob_fsp: storing blob length %u on file %s\n",
140                   (unsigned int)pblob->length, fsp_str_dbg(fsp)));
141
142         become_root();
143         if (fsp->fh->fd != -1) {
144                 ret = SMB_VFS_FSETXATTR(fsp, XATTR_NTACL_NAME,
145                         pblob->data, pblob->length, 0);
146         } else {
147                 ret = SMB_VFS_SETXATTR(fsp->conn, fsp->fsp_name->base_name,
148                                 XATTR_NTACL_NAME,
149                                 pblob->data, pblob->length, 0);
150         }
151         if (ret) {
152                 saved_errno = errno;
153         }
154         unbecome_root();
155         if (ret) {
156                 DEBUG(5, ("store_acl_blob_fsp: setting attr failed for file %s"
157                         "with error %s\n",
158                         fsp_str_dbg(fsp),
159                         strerror(saved_errno) ));
160                 errno = saved_errno;
161                 return map_nt_error_from_unix(saved_errno);
162         }
163         return NT_STATUS_OK;
164 }
165
166 /*********************************************************************
167  Remove a Windows ACL - we're setting the underlying POSIX ACL.
168 *********************************************************************/
169
170 static int sys_acl_set_file_xattr(vfs_handle_struct *handle,
171                               const char *name,
172                               SMB_ACL_TYPE_T type,
173                               SMB_ACL_T theacl)
174 {
175         int ret = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle,
176                                                 name,
177                                                 type,
178                                                 theacl);
179         if (ret == -1) {
180                 return -1;
181         }
182
183         become_root();
184         SMB_VFS_REMOVEXATTR(handle->conn, name, XATTR_NTACL_NAME);
185         unbecome_root();
186
187         return ret;
188 }
189
190 /*********************************************************************
191  Remove a Windows ACL - we're setting the underlying POSIX ACL.
192 *********************************************************************/
193
194 static int sys_acl_set_fd_xattr(vfs_handle_struct *handle,
195                             files_struct *fsp,
196                             SMB_ACL_T theacl)
197 {
198         int ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle,
199                                                 fsp,
200                                                 theacl);
201         if (ret == -1) {
202                 return -1;
203         }
204
205         become_root();
206         SMB_VFS_FREMOVEXATTR(fsp, XATTR_NTACL_NAME);
207         unbecome_root();
208
209         return ret;
210 }
211
212 static int connect_acl_xattr(struct vfs_handle_struct *handle,
213                                 const char *service,
214                                 const char *user)
215 {
216         int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
217         bool ok;
218         struct acl_common_config *config = NULL;
219
220         if (ret < 0) {
221                 return ret;
222         }
223
224         ok = init_acl_common_config(handle);
225         if (!ok) {
226                 DBG_ERR("init_acl_common_config failed\n");
227                 return -1;
228         }
229
230         /* Ensure we have the parameters correct if we're
231          * using this module. */
232         DEBUG(2,("connect_acl_xattr: setting 'inherit acls = true' "
233                 "'dos filemode = true' and "
234                 "'force unknown acl user = true' for service %s\n",
235                 service ));
236
237         lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
238         lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
239         lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
240
241         SMB_VFS_HANDLE_GET_DATA(handle, config,
242                                 struct acl_common_config,
243                                 return -1);
244
245         if (config->ignore_system_acls) {
246                 mode_t create_mask = lp_create_mask(SNUM(handle->conn));
247                 char *create_mask_str = NULL;
248
249                 if ((create_mask & 0666) != 0666) {
250                         create_mask |= 0666;
251                         create_mask_str = talloc_asprintf(handle, "0%o",
252                                                           create_mask);
253                         if (create_mask_str == NULL) {
254                                 DBG_ERR("talloc_asprintf failed\n");
255                                 return -1;
256                         }
257
258                         DBG_NOTICE("setting 'create mask = %s'\n", create_mask_str);
259
260                         lp_do_parameter (SNUM(handle->conn),
261                                         "create mask", create_mask_str);
262
263                         TALLOC_FREE(create_mask_str);
264                 }
265
266                 DBG_NOTICE("setting 'directory mask = 0777', "
267                            "'store dos attributes = yes' and all "
268                            "'map ...' options to 'no'\n");
269
270                 lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
271                 lp_do_parameter(SNUM(handle->conn), "map archive", "no");
272                 lp_do_parameter(SNUM(handle->conn), "map hidden", "no");
273                 lp_do_parameter(SNUM(handle->conn), "map readonly", "no");
274                 lp_do_parameter(SNUM(handle->conn), "map system", "no");
275                 lp_do_parameter(SNUM(handle->conn), "store dos attributes",
276                                 "yes");
277         }
278
279         return 0;
280 }
281
282 static struct vfs_fn_pointers vfs_acl_xattr_fns = {
283         .connect_fn = connect_acl_xattr,
284         .rmdir_fn = rmdir_acl_common,
285         .unlink_fn = unlink_acl_common,
286         .chmod_fn = chmod_acl_module_common,
287         .fchmod_fn = fchmod_acl_module_common,
288         .fget_nt_acl_fn = fget_nt_acl_common,
289         .get_nt_acl_fn = get_nt_acl_common,
290         .fset_nt_acl_fn = fset_nt_acl_common,
291         .chmod_acl_fn = chmod_acl_acl_module_common,
292         .fchmod_acl_fn = fchmod_acl_acl_module_common,
293         .sys_acl_set_file_fn = sys_acl_set_file_xattr,
294         .sys_acl_set_fd_fn = sys_acl_set_fd_xattr
295 };
296
297 static_decl_vfs;
298 NTSTATUS vfs_acl_xattr_init(TALLOC_CTX *ctx)
299 {
300         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "acl_xattr",
301                                 &vfs_acl_xattr_fns);
302 }