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
)
194 enum ndr_err_code ndr_err
;
195 /* For now, ACLs are allocated on NULL */
196 struct smb_acl_t
*acl
= talloc(NULL
, struct smb_acl_t
);
202 ndr_err
= ndr_pull_struct_blob(blob
, acl
, acl
,
203 (ndr_pull_flags_fn_t
)ndr_pull_smb_acl_t
);
205 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
206 DEBUG(0, ("ndr_pull_acl_t failed: %s\n",
207 ndr_errstr(ndr_err
)));
214 static DATA_BLOB
fake_acls_acl2blob(TALLOC_CTX
*mem_ctx
, SMB_ACL_T acl
)
216 enum ndr_err_code ndr_err
;
218 ndr_err
= ndr_push_struct_blob(&blob
, mem_ctx
, acl
,
219 (ndr_push_flags_fn_t
)ndr_push_smb_acl_t
);
221 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
222 DEBUG(0, ("ndr_push_acl_t failed: %s\n",
223 ndr_errstr(ndr_err
)));
224 return data_blob_null
;
229 static SMB_ACL_T
fake_acls_sys_acl_get_file(struct vfs_handle_struct
*handle
, const char *path
, SMB_ACL_TYPE_T type
)
231 DATA_BLOB blob
= data_blob_null
;
233 const char *name
= NULL
;
234 struct smb_acl_t
*acl
= NULL
;
235 TALLOC_CTX
*frame
= talloc_stackframe();
237 case SMB_ACL_TYPE_ACCESS
:
238 name
= FAKE_ACL_ACCESS_XATTR
;
240 case SMB_ACL_TYPE_DEFAULT
:
241 name
= FAKE_ACL_DEFAULT_XATTR
;
247 blob
.data
= talloc_realloc(frame
, blob
.data
, uint8_t, blob
.length
);
253 length
= SMB_VFS_NEXT_GETXATTR(handle
, path
, name
, blob
.data
, blob
.length
);
254 blob
.length
= length
;
255 } while (length
== -1 && errno
== ERANGE
);
256 if (length
== -1 && errno
== ENOATTR
) {
261 acl
= fake_acls_blob2acl(&blob
);
267 static SMB_ACL_T
fake_acls_sys_acl_get_fd(struct vfs_handle_struct
*handle
, files_struct
*fsp
)
269 DATA_BLOB blob
= data_blob_null
;
271 const char *name
= FAKE_ACL_ACCESS_XATTR
;
272 struct smb_acl_t
*acl
;
273 TALLOC_CTX
*frame
= talloc_stackframe();
277 blob
.data
= talloc_realloc(frame
, blob
.data
, uint8_t, blob
.length
);
283 length
= SMB_VFS_NEXT_FGETXATTR(handle
, fsp
, name
, blob
.data
, blob
.length
);
284 blob
.length
= length
;
285 } while (length
== -1 && errno
== ERANGE
);
286 if (length
== -1 && errno
== ENOATTR
) {
291 acl
= fake_acls_blob2acl(&blob
);
297 static int fake_acls_sys_acl_set_file(vfs_handle_struct
*handle
, const char *path
, SMB_ACL_TYPE_T acltype
, SMB_ACL_T theacl
)
300 const char *name
= NULL
;
301 TALLOC_CTX
*frame
= talloc_stackframe();
302 DATA_BLOB blob
= fake_acls_acl2blob(frame
, theacl
);
304 DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n"));
310 case SMB_ACL_TYPE_ACCESS
:
311 name
= FAKE_ACL_ACCESS_XATTR
;
313 case SMB_ACL_TYPE_DEFAULT
:
314 name
= FAKE_ACL_DEFAULT_XATTR
;
317 ret
= SMB_VFS_NEXT_SETXATTR(handle
, path
, name
, blob
.data
, blob
.length
, 0);
322 static int fake_acls_sys_acl_set_fd(vfs_handle_struct
*handle
, files_struct
*fsp
, SMB_ACL_T theacl
)
325 const char *name
= FAKE_ACL_ACCESS_XATTR
;
326 TALLOC_CTX
*frame
= talloc_stackframe();
327 DATA_BLOB blob
= fake_acls_acl2blob(frame
, theacl
);
329 DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n"));
334 ret
= SMB_VFS_NEXT_FSETXATTR(handle
, fsp
, name
, blob
.data
, blob
.length
, 0);
339 static int fake_acls_sys_acl_delete_def_file(vfs_handle_struct
*handle
, const char *path
)
342 const char *name
= FAKE_ACL_DEFAULT_XATTR
;
343 TALLOC_CTX
*frame
= talloc_stackframe();
344 struct smb_filename
*smb_fname
= NULL
;
345 NTSTATUS status
= create_synthetic_smb_fname_split(frame
, path
, NULL
,
347 if (!NT_STATUS_IS_OK(status
)) {
348 errno
= map_errno_from_nt_status(status
);
353 ret
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
359 if (!S_ISDIR(smb_fname
->st
.st_ex_mode
)) {
365 ret
= SMB_VFS_NEXT_REMOVEXATTR(handle
, path
, name
);
366 if (ret
== -1 && errno
== ENOATTR
) {
375 static int fake_acls_chown(vfs_handle_struct
*handle
, const char *path
, uid_t uid
, gid_t gid
)
380 SIVAL(id_buf
, 0, uid
);
381 ret
= SMB_VFS_NEXT_SETXATTR(handle
, path
, FAKE_UID
, id_buf
, sizeof(id_buf
), 0);
387 SIVAL(id_buf
, 0, gid
);
388 ret
= SMB_VFS_NEXT_SETXATTR(handle
, path
, FAKE_GID
, id_buf
, sizeof(id_buf
), 0);
396 static int fake_acls_lchown(vfs_handle_struct
*handle
, const char *path
, uid_t uid
, gid_t gid
)
401 /* This isn't quite right (calling setxattr not
402 * lsetxattr), but for the test purposes of this
403 * module (fake NT ACLs from windows clients), it is
404 * close enough. We removed the l*xattr functions
405 * because linux doesn't support using them, but we
406 * could fake them in xattr_tdb if we really wanted
409 SIVAL(id_buf
, 0, uid
);
410 ret
= SMB_VFS_NEXT_SETXATTR(handle
, path
, FAKE_UID
, id_buf
, sizeof(id_buf
), 0);
416 SIVAL(id_buf
, 0, gid
);
417 ret
= SMB_VFS_NEXT_SETXATTR(handle
, path
, FAKE_GID
, id_buf
, sizeof(id_buf
), 0);
425 static int fake_acls_fchown(vfs_handle_struct
*handle
, files_struct
*fsp
, uid_t uid
, gid_t gid
)
430 SIVAL(id_buf
, 0, uid
);
431 ret
= SMB_VFS_NEXT_FSETXATTR(handle
, fsp
, FAKE_UID
, id_buf
, sizeof(id_buf
), 0);
437 SIVAL(id_buf
, 0, gid
);
438 ret
= SMB_VFS_NEXT_FSETXATTR(handle
, fsp
, FAKE_GID
, id_buf
, sizeof(id_buf
), 0);
447 static struct vfs_fn_pointers vfs_fake_acls_fns
= {
448 .stat_fn
= fake_acls_stat
,
449 .lstat_fn
= fake_acls_lstat
,
450 .fstat_fn
= fake_acls_fstat
,
451 .sys_acl_get_file_fn
= fake_acls_sys_acl_get_file
,
452 .sys_acl_get_fd_fn
= fake_acls_sys_acl_get_fd
,
453 .sys_acl_set_file_fn
= fake_acls_sys_acl_set_file
,
454 .sys_acl_set_fd_fn
= fake_acls_sys_acl_set_fd
,
455 .sys_acl_delete_def_file_fn
= fake_acls_sys_acl_delete_def_file
,
456 .chown_fn
= fake_acls_chown
,
457 .lchown_fn
= fake_acls_lchown
,
458 .fchown_fn
= fake_acls_fchown
,
462 NTSTATUS
vfs_fake_acls_init(void);
463 NTSTATUS
vfs_fake_acls_init(void)
465 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "fake_acls",