s3-vfs: Correct the implementation of fake_acls_sys_acl_delete_def_file()
[Samba/gebeck_regimport.git] / source3 / modules / vfs_fake_acls.c
blobd7398a2ebff5cdc2e1d9c511424e92eb723508e8
1 /*
2 * Fake ACLs VFS module. Implements passthrough operation of all VFS
3 * calls to disk functions, except for file ownership and ACLs, which
4 * are stored in xattrs.
6 * Copyright (C) Tim Potter, 1999-2000
7 * Copyright (C) Alexander Bokovoy, 2002
8 * Copyright (C) Andrew Bartlett, 2002,2012
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <http://www.gnu.org/licenses/>.
24 #include "includes.h"
25 #include "smbd/smbd.h"
26 #include "system/filesys.h"
27 #include "auth.h"
28 #include "librpc/gen_ndr/ndr_smb_acl.h"
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_VFS
33 #define FAKE_UID "system.fake_uid"
34 #define FAKE_GID "system.fake_gid"
35 #define FAKE_ACL_ACCESS_XATTR "system.fake_access_acl"
36 #define FAKE_ACL_DEFAULT_XATTR "system.fake_default_acl"
38 static int fake_acls_uid(vfs_handle_struct *handle,
39 const char *path,
40 uid_t *uid)
42 ssize_t size;
43 uint8_t uid_buf[4];
44 size = SMB_VFS_NEXT_GETXATTR(handle, path, FAKE_UID, uid_buf, sizeof(uid_buf));
45 if (size == -1 && errno == ENOATTR) {
46 return 0;
48 if (size != 4) {
49 return -1;
51 *uid = IVAL(uid_buf, 0);
52 return 0;
55 static int fake_acls_gid(vfs_handle_struct *handle,
56 const char *path,
57 uid_t *gid)
59 ssize_t size;
60 uint8_t gid_buf[4];
62 size = SMB_VFS_NEXT_GETXATTR(handle, path, FAKE_GID, gid_buf, sizeof(gid_buf));
63 if (size == -1 && errno == ENOATTR) {
64 return 0;
66 if (size != 4) {
67 return -1;
69 *gid = IVAL(gid_buf, 0);
70 return 0;
73 static int fake_acls_fuid(vfs_handle_struct *handle,
74 files_struct *fsp,
75 uid_t *uid)
77 ssize_t size;
78 uint8_t uid_buf[4];
80 size = SMB_VFS_NEXT_FGETXATTR(handle, fsp, FAKE_UID, uid_buf, sizeof(uid_buf));
81 if (size == -1 && errno == ENOATTR) {
82 return 0;
84 if (size != 4) {
85 return -1;
87 *uid = IVAL(uid_buf, 0);
88 return 0;
91 static int fake_acls_fgid(vfs_handle_struct *handle,
92 files_struct *fsp,
93 uid_t *gid)
95 ssize_t size;
96 uint8_t gid_buf[4];
98 size = SMB_VFS_NEXT_FGETXATTR(handle, fsp, FAKE_GID, gid_buf, sizeof(gid_buf));
99 if (size == -1 && errno == ENOATTR) {
100 return 0;
102 if (size != 4) {
103 return -1;
105 *gid = IVAL(gid_buf, 0);
106 return 0;
109 static int fake_acls_stat(vfs_handle_struct *handle,
110 struct smb_filename *smb_fname)
112 int ret = -1;
114 ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
115 if (ret == 0) {
116 TALLOC_CTX *frame = talloc_stackframe();
117 char *path;
118 NTSTATUS status;
119 status = get_full_smb_filename(frame, smb_fname, &path);
120 if (!NT_STATUS_IS_OK(status)) {
121 errno = map_errno_from_nt_status(status);
122 TALLOC_FREE(frame);
123 return -1;
126 ret = fake_acls_uid(handle, path, &smb_fname->st.st_ex_uid);
127 if (ret != 0) {
128 TALLOC_FREE(frame);
129 return ret;
131 ret = fake_acls_gid(handle, path, &smb_fname->st.st_ex_gid);
132 if (ret != 0) {
133 TALLOC_FREE(frame);
134 return ret;
136 TALLOC_FREE(frame);
139 return ret;
142 static int fake_acls_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
144 int ret = -1;
146 ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
147 if (ret == 0) {
148 ret = fake_acls_fuid(handle, fsp, &sbuf->st_ex_uid);
149 if (ret != 0) {
150 return ret;
152 ret = fake_acls_fgid(handle, fsp, &sbuf->st_ex_gid);
153 if (ret != 0) {
154 return ret;
157 return ret;
160 static SMB_ACL_T fake_acls_blob2acl(DATA_BLOB *blob)
162 enum ndr_err_code ndr_err;
163 /* For now, ACLs are allocated on NULL */
164 struct smb_acl_t *acl = talloc(NULL, struct smb_acl_t);
165 if (!acl) {
166 errno = ENOMEM;
167 return NULL;
170 ndr_err = ndr_pull_struct_blob(blob, acl, acl,
171 (ndr_pull_flags_fn_t)ndr_pull_smb_acl_t);
173 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
174 DEBUG(0, ("ndr_pull_acl_t failed: %s\n",
175 ndr_errstr(ndr_err)));
176 TALLOC_FREE(acl);
177 return NULL;
179 return acl;
182 static DATA_BLOB fake_acls_acl2blob(TALLOC_CTX *mem_ctx, SMB_ACL_T acl)
184 enum ndr_err_code ndr_err;
185 DATA_BLOB blob;
186 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, acl,
187 (ndr_push_flags_fn_t)ndr_push_smb_acl_t);
189 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
190 DEBUG(0, ("ndr_push_acl_t failed: %s\n",
191 ndr_errstr(ndr_err)));
192 return data_blob_null;
194 return blob;
197 static SMB_ACL_T fake_acls_sys_acl_get_file(struct vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T type)
199 DATA_BLOB blob = data_blob_null;
200 ssize_t length;
201 const char *name = NULL;
202 struct smb_acl_t *acl = NULL;
203 TALLOC_CTX *frame = talloc_stackframe();
204 switch (type) {
205 case SMB_ACL_TYPE_ACCESS:
206 name = FAKE_ACL_ACCESS_XATTR;
207 break;
208 case SMB_ACL_TYPE_DEFAULT:
209 name = FAKE_ACL_DEFAULT_XATTR;
210 break;
213 do {
214 blob.length += 1000;
215 blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
216 if (!blob.data) {
217 errno = ENOMEM;
218 TALLOC_FREE(frame);
219 return NULL;
221 length = SMB_VFS_NEXT_GETXATTR(handle, path, name, blob.data, blob.length);
222 blob.length = length;
223 } while (length == -1 && errno == ERANGE);
224 if (length == -1 && errno == ENOATTR) {
225 TALLOC_FREE(frame);
226 return NULL;
228 if (length != -1) {
229 acl = fake_acls_blob2acl(&blob);
231 TALLOC_FREE(frame);
232 return acl;
235 static SMB_ACL_T fake_acls_sys_acl_get_fd(struct vfs_handle_struct *handle, files_struct *fsp)
237 DATA_BLOB blob = data_blob_null;
238 ssize_t length;
239 const char *name = FAKE_ACL_ACCESS_XATTR;
240 struct smb_acl_t *acl;
241 TALLOC_CTX *frame = talloc_stackframe();
243 do {
244 blob.length += 1000;
245 blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
246 if (!blob.data) {
247 errno = ENOMEM;
248 TALLOC_FREE(frame);
249 return NULL;
251 length = SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, blob.data, blob.length);
252 blob.length = length;
253 } while (length == -1 && errno == ERANGE);
254 if (length == -1 && errno == ENOATTR) {
255 TALLOC_FREE(frame);
256 return NULL;
258 if (length != -1) {
259 acl = fake_acls_blob2acl(&blob);
261 TALLOC_FREE(frame);
262 return acl;
265 static int fake_acls_sys_acl_set_file(vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
267 int ret;
268 const char *name = NULL;
269 TALLOC_CTX *frame = talloc_stackframe();
270 DATA_BLOB blob = fake_acls_acl2blob(frame, theacl);
271 if (!blob.data) {
272 DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n"));
273 TALLOC_FREE(frame);
274 errno = EINVAL;
275 return -1;
277 switch (acltype) {
278 case SMB_ACL_TYPE_ACCESS:
279 name = FAKE_ACL_ACCESS_XATTR;
280 break;
281 case SMB_ACL_TYPE_DEFAULT:
282 name = FAKE_ACL_DEFAULT_XATTR;
283 break;
285 ret = SMB_VFS_NEXT_SETXATTR(handle, path, name, blob.data, blob.length, 0);
286 TALLOC_FREE(frame);
287 return ret;
290 static int fake_acls_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, SMB_ACL_T theacl)
292 int ret;
293 const char *name = FAKE_ACL_ACCESS_XATTR;
294 TALLOC_CTX *frame = talloc_stackframe();
295 DATA_BLOB blob = fake_acls_acl2blob(frame, theacl);
296 if (!blob.data) {
297 DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n"));
298 TALLOC_FREE(frame);
299 errno = EINVAL;
300 return -1;
302 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, blob.data, blob.length, 0);
303 TALLOC_FREE(frame);
304 return ret;
307 static int fake_acls_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path)
309 int ret;
310 const char *name = FAKE_ACL_DEFAULT_XATTR;
311 TALLOC_CTX *frame = talloc_stackframe();
312 struct smb_filename *smb_fname = NULL;
313 NTSTATUS status = create_synthetic_smb_fname_split(frame, path, NULL,
314 &smb_fname);
315 if (!NT_STATUS_IS_OK(status)) {
316 errno = map_errno_from_nt_status(status);
317 TALLOC_FREE(frame);
318 return -1;
321 ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
322 if (ret == -1) {
323 TALLOC_FREE(frame);
324 return -1;
327 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
328 errno = EINVAL;
329 TALLOC_FREE(frame);
330 return -1;
333 ret = SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
334 if (ret == -1 && errno == ENOATTR) {
335 ret = 0;
336 errno = 0;
339 TALLOC_FREE(frame);
340 return ret;
343 static int fake_acls_chown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
345 int ret;
346 uint8_t id_buf[4];
347 if (uid != -1) {
348 SIVAL(id_buf, 0, uid);
349 ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_UID, id_buf, sizeof(id_buf), 0);
350 if (ret != 0) {
351 return ret;
354 if (gid != -1) {
355 SIVAL(id_buf, 0, gid);
356 ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_GID, id_buf, sizeof(id_buf), 0);
357 if (ret != 0) {
358 return ret;
361 return 0;
364 static int fake_acls_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
366 int ret;
367 uint8_t id_buf[4];
368 if (uid != -1) {
369 SIVAL(id_buf, 0, uid);
370 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, FAKE_UID, id_buf, sizeof(id_buf), 0);
371 if (ret != 0) {
372 return ret;
375 if (gid != -1) {
376 SIVAL(id_buf, 0, gid);
377 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, FAKE_GID, id_buf, sizeof(id_buf), 0);
378 if (ret != 0) {
379 return ret;
382 return 0;
386 static struct vfs_fn_pointers vfs_fake_acls_fns = {
387 .stat_fn = fake_acls_stat,
388 .fstat_fn = fake_acls_fstat,
389 .sys_acl_get_file_fn = fake_acls_sys_acl_get_file,
390 .sys_acl_get_fd_fn = fake_acls_sys_acl_get_fd,
391 .sys_acl_set_file_fn = fake_acls_sys_acl_set_file,
392 .sys_acl_set_fd_fn = fake_acls_sys_acl_set_fd,
393 .sys_acl_delete_def_file_fn = fake_acls_sys_acl_delete_def_file,
394 .chown_fn = fake_acls_chown,
395 .fchown_fn = fake_acls_fchown,
399 NTSTATUS vfs_fake_acls_init(void);
400 NTSTATUS vfs_fake_acls_init(void)
402 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "fake_acls",
403 &vfs_fake_acls_fns);