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/>.
25 #include "smbd/smbd.h"
26 #include "system/filesys.h"
28 #include "librpc/gen_ndr/ndr_smb_acl.h"
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,
44 size = SMB_VFS_NEXT_GETXATTR(handle, path, FAKE_UID, uid_buf, sizeof(uid_buf));
45 if (size == -1 && errno == ENOATTR) {
51 *uid = IVAL(uid_buf, 0);
55 static int fake_acls_gid(vfs_handle_struct *handle,
62 size = SMB_VFS_NEXT_GETXATTR(handle, path, FAKE_GID, gid_buf, sizeof(gid_buf));
63 if (size == -1 && errno == ENOATTR) {
69 *gid = IVAL(gid_buf, 0);
73 static int fake_acls_fuid(vfs_handle_struct *handle,
80 size = SMB_VFS_NEXT_FGETXATTR(handle, fsp, FAKE_UID, uid_buf, sizeof(uid_buf));
81 if (size == -1 && errno == ENOATTR) {
87 *uid = IVAL(uid_buf, 0);
91 static int fake_acls_fgid(vfs_handle_struct *handle,
98 size = SMB_VFS_NEXT_FGETXATTR(handle, fsp, FAKE_GID, gid_buf, sizeof(gid_buf));
99 if (size == -1 && errno == ENOATTR) {
105 *gid = IVAL(gid_buf, 0);
109 static int fake_acls_stat(vfs_handle_struct *handle,
110 struct smb_filename *smb_fname)
114 ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
116 TALLOC_CTX *frame = talloc_stackframe();
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);
126 ret = fake_acls_uid(handle, path, &smb_fname->st.st_ex_uid);
131 ret = fake_acls_gid(handle, path, &smb_fname->st.st_ex_gid);
142 static int fake_acls_lstat(vfs_handle_struct *handle,
143 struct smb_filename *smb_fname)
147 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
149 TALLOC_CTX *frame = talloc_stackframe();
152 status = get_full_smb_filename(frame, smb_fname, &path);
153 if (!NT_STATUS_IS_OK(status)) {
154 errno = map_errno_from_nt_status(status);
159 /* This isn't quite right (calling getxattr not
160 * lgetxattr), but for the test purposes of this
161 * module (fake NT ACLs from windows clients), it is
162 * close enough. We removed the l*xattr functions
163 * because linux doesn't support using them, but we
164 * could fake them in xattr_tdb if we really wanted
165 * to. We ignore errors because the link might not point anywhere */
166 fake_acls_uid(handle, path, &smb_fname->st.st_ex_uid);
167 fake_acls_gid(handle, path, &smb_fname->st.st_ex_gid);
174 static int fake_acls_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
178 ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
180 ret = fake_acls_fuid(handle, fsp, &sbuf->st_ex_uid);
184 ret = fake_acls_fgid(handle, fsp, &sbuf->st_ex_gid);
192 static SMB_ACL_T fake_acls_blob2acl(DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
194 enum ndr_err_code ndr_err;
195 struct smb_acl_t *acl = talloc(mem_ctx, struct smb_acl_t);
201 ndr_err = ndr_pull_struct_blob(blob, acl, acl,
202 (ndr_pull_flags_fn_t)ndr_pull_smb_acl_t);
204 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
205 DEBUG(0, ("ndr_pull_acl_t failed: %s\n",
206 ndr_errstr(ndr_err)));
213 static DATA_BLOB fake_acls_acl2blob(TALLOC_CTX *mem_ctx, SMB_ACL_T acl)
215 enum ndr_err_code ndr_err;
217 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, acl,
218 (ndr_push_flags_fn_t)ndr_push_smb_acl_t);
220 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
221 DEBUG(0, ("ndr_push_acl_t failed: %s\n",
222 ndr_errstr(ndr_err)));
223 return data_blob_null;
228 static SMB_ACL_T fake_acls_sys_acl_get_file(struct vfs_handle_struct *handle,
233 DATA_BLOB blob = data_blob_null;
235 const char *name = NULL;
236 struct smb_acl_t *acl = NULL;
237 TALLOC_CTX *frame = talloc_stackframe();
239 case SMB_ACL_TYPE_ACCESS:
240 name = FAKE_ACL_ACCESS_XATTR;
242 case SMB_ACL_TYPE_DEFAULT:
243 name = FAKE_ACL_DEFAULT_XATTR;
249 blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
255 length = SMB_VFS_NEXT_GETXATTR(handle, path, name, blob.data, blob.length);
256 blob.length = length;
257 } while (length == -1 && errno == ERANGE);
258 if (length == -1 && errno == ENOATTR) {
263 acl = fake_acls_blob2acl(&blob, mem_ctx);
269 static SMB_ACL_T fake_acls_sys_acl_get_fd(struct vfs_handle_struct *handle,
273 DATA_BLOB blob = data_blob_null;
275 const char *name = FAKE_ACL_ACCESS_XATTR;
276 struct smb_acl_t *acl = NULL;
277 TALLOC_CTX *frame = talloc_stackframe();
281 blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
287 length = SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, blob.data, blob.length);
288 blob.length = length;
289 } while (length == -1 && errno == ERANGE);
290 if (length == -1 && errno == ENOATTR) {
295 acl = fake_acls_blob2acl(&blob, mem_ctx);
302 static int fake_acls_sys_acl_set_file(vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
305 const char *name = NULL;
306 TALLOC_CTX *frame = talloc_stackframe();
307 DATA_BLOB blob = fake_acls_acl2blob(frame, theacl);
309 DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n"));
315 case SMB_ACL_TYPE_ACCESS:
316 name = FAKE_ACL_ACCESS_XATTR;
318 case SMB_ACL_TYPE_DEFAULT:
319 name = FAKE_ACL_DEFAULT_XATTR;
322 ret = SMB_VFS_NEXT_SETXATTR(handle, path, name, blob.data, blob.length, 0);
327 static int fake_acls_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, SMB_ACL_T theacl)
330 const char *name = FAKE_ACL_ACCESS_XATTR;
331 TALLOC_CTX *frame = talloc_stackframe();
332 DATA_BLOB blob = fake_acls_acl2blob(frame, theacl);
334 DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n"));
339 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, blob.data, blob.length, 0);
344 static int fake_acls_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path)
347 const char *name = FAKE_ACL_DEFAULT_XATTR;
348 TALLOC_CTX *frame = talloc_stackframe();
349 struct smb_filename *smb_fname = NULL;
350 NTSTATUS status = create_synthetic_smb_fname_split(frame, path, NULL,
352 if (!NT_STATUS_IS_OK(status)) {
353 errno = map_errno_from_nt_status(status);
358 ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
364 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
370 ret = SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
371 if (ret == -1 && errno == ENOATTR) {
380 static int fake_acls_chown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
385 SIVAL(id_buf, 0, uid);
386 ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_UID, id_buf, sizeof(id_buf), 0);
392 SIVAL(id_buf, 0, gid);
393 ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_GID, id_buf, sizeof(id_buf), 0);
401 static int fake_acls_lchown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
406 /* This isn't quite right (calling setxattr not
407 * lsetxattr), but for the test purposes of this
408 * module (fake NT ACLs from windows clients), it is
409 * close enough. We removed the l*xattr functions
410 * because linux doesn't support using them, but we
411 * could fake them in xattr_tdb if we really wanted
414 SIVAL(id_buf, 0, uid);
415 ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_UID, id_buf, sizeof(id_buf), 0);
421 SIVAL(id_buf, 0, gid);
422 ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_GID, id_buf, sizeof(id_buf), 0);
430 static int fake_acls_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
435 SIVAL(id_buf, 0, uid);
436 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, FAKE_UID, id_buf, sizeof(id_buf), 0);
442 SIVAL(id_buf, 0, gid);
443 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, FAKE_GID, id_buf, sizeof(id_buf), 0);
452 static struct vfs_fn_pointers vfs_fake_acls_fns = {
453 .stat_fn = fake_acls_stat,
454 .lstat_fn = fake_acls_lstat,
455 .fstat_fn = fake_acls_fstat,
456 .sys_acl_get_file_fn = fake_acls_sys_acl_get_file,
457 .sys_acl_get_fd_fn = fake_acls_sys_acl_get_fd,
458 .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
459 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
460 .sys_acl_set_file_fn = fake_acls_sys_acl_set_file,
461 .sys_acl_set_fd_fn = fake_acls_sys_acl_set_fd,
462 .sys_acl_delete_def_file_fn = fake_acls_sys_acl_delete_def_file,
463 .chown_fn = fake_acls_chown,
464 .lchown_fn = fake_acls_lchown,
465 .fchown_fn = fake_acls_fchown,
469 NTSTATUS vfs_fake_acls_init(void);
470 NTSTATUS vfs_fake_acls_init(void)
472 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "fake_acls",