s3: VFS: Change SMB_VFS_SETXATTR to use const struct smb_filename * instead of const...
[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,
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 struct smb_filename *smb_fname,
172                                 SMB_ACL_TYPE_T type,
173                                 SMB_ACL_T theacl)
174 {
175         int ret = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle,
176                                                 smb_fname,
177                                                 type,
178                                                 theacl);
179         if (ret == -1) {
180                 return -1;
181         }
182
183         become_root();
184         SMB_VFS_REMOVEXATTR(handle->conn, smb_fname,
185                         XATTR_NTACL_NAME);
186         unbecome_root();
187
188         return ret;
189 }
190
191 /*********************************************************************
192  Remove a Windows ACL - we're setting the underlying POSIX ACL.
193 *********************************************************************/
194
195 static int sys_acl_set_fd_xattr(vfs_handle_struct *handle,
196                             files_struct *fsp,
197                             SMB_ACL_T theacl)
198 {
199         int ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle,
200                                                 fsp,
201                                                 theacl);
202         if (ret == -1) {
203                 return -1;
204         }
205
206         become_root();
207         SMB_VFS_FREMOVEXATTR(fsp, XATTR_NTACL_NAME);
208         unbecome_root();
209
210         return ret;
211 }
212
213 static int connect_acl_xattr(struct vfs_handle_struct *handle,
214                                 const char *service,
215                                 const char *user)
216 {
217         int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
218         bool ok;
219         struct acl_common_config *config = NULL;
220
221         if (ret < 0) {
222                 return ret;
223         }
224
225         ok = init_acl_common_config(handle);
226         if (!ok) {
227                 DBG_ERR("init_acl_common_config failed\n");
228                 return -1;
229         }
230
231         /* Ensure we have the parameters correct if we're
232          * using this module. */
233         DEBUG(2,("connect_acl_xattr: setting 'inherit acls = true' "
234                 "'dos filemode = true' and "
235                 "'force unknown acl user = true' for service %s\n",
236                 service ));
237
238         lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
239         lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
240         lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
241
242         SMB_VFS_HANDLE_GET_DATA(handle, config,
243                                 struct acl_common_config,
244                                 return -1);
245
246         if (config->ignore_system_acls) {
247                 mode_t create_mask = lp_create_mask(SNUM(handle->conn));
248                 char *create_mask_str = NULL;
249
250                 if ((create_mask & 0666) != 0666) {
251                         create_mask |= 0666;
252                         create_mask_str = talloc_asprintf(handle, "0%o",
253                                                           create_mask);
254                         if (create_mask_str == NULL) {
255                                 DBG_ERR("talloc_asprintf failed\n");
256                                 return -1;
257                         }
258
259                         DBG_NOTICE("setting 'create mask = %s'\n", create_mask_str);
260
261                         lp_do_parameter (SNUM(handle->conn),
262                                         "create mask", create_mask_str);
263
264                         TALLOC_FREE(create_mask_str);
265                 }
266
267                 DBG_NOTICE("setting 'directory mask = 0777', "
268                            "'store dos attributes = yes' and all "
269                            "'map ...' options to 'no'\n");
270
271                 lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
272                 lp_do_parameter(SNUM(handle->conn), "map archive", "no");
273                 lp_do_parameter(SNUM(handle->conn), "map hidden", "no");
274                 lp_do_parameter(SNUM(handle->conn), "map readonly", "no");
275                 lp_do_parameter(SNUM(handle->conn), "map system", "no");
276                 lp_do_parameter(SNUM(handle->conn), "store dos attributes",
277                                 "yes");
278         }
279
280         return 0;
281 }
282
283 static struct vfs_fn_pointers vfs_acl_xattr_fns = {
284         .connect_fn = connect_acl_xattr,
285         .rmdir_fn = rmdir_acl_common,
286         .unlink_fn = unlink_acl_common,
287         .chmod_fn = chmod_acl_module_common,
288         .fchmod_fn = fchmod_acl_module_common,
289         .fget_nt_acl_fn = fget_nt_acl_common,
290         .get_nt_acl_fn = get_nt_acl_common,
291         .fset_nt_acl_fn = fset_nt_acl_common,
292         .chmod_acl_fn = chmod_acl_acl_module_common,
293         .fchmod_acl_fn = fchmod_acl_acl_module_common,
294         .sys_acl_set_file_fn = sys_acl_set_file_xattr,
295         .sys_acl_set_fd_fn = sys_acl_set_fd_xattr
296 };
297
298 static_decl_vfs;
299 NTSTATUS vfs_acl_xattr_init(TALLOC_CTX *ctx)
300 {
301         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "acl_xattr",
302                                 &vfs_acl_xattr_fns);
303 }