tombstones-expunge: Add a test for deleting links to recycled objects
[Samba.git] / source3 / modules / vfs_fake_acls.c
blob55ff7db37df31e9c91271bd29c8bce9d5a061fba
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 struct smb_filename smb_fname_base = {
119 .base_name = smb_fname->base_name
121 NTSTATUS status;
123 * As we're calling getxattr directly here
124 * we need to use only the base_name, not
125 * the full name containing any stream name.
127 status = get_full_smb_filename(frame, &smb_fname_base, &path);
128 if (!NT_STATUS_IS_OK(status)) {
129 errno = map_errno_from_nt_status(status);
130 TALLOC_FREE(frame);
131 return -1;
134 ret = fake_acls_uid(handle, path, &smb_fname->st.st_ex_uid);
135 if (ret != 0) {
136 TALLOC_FREE(frame);
137 return ret;
139 ret = fake_acls_gid(handle, path, &smb_fname->st.st_ex_gid);
140 if (ret != 0) {
141 TALLOC_FREE(frame);
142 return ret;
144 TALLOC_FREE(frame);
147 return ret;
150 static int fake_acls_lstat(vfs_handle_struct *handle,
151 struct smb_filename *smb_fname)
153 int ret = -1;
155 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
156 if (ret == 0) {
157 TALLOC_CTX *frame = talloc_stackframe();
158 char *path;
159 struct smb_filename smb_fname_base = {
160 .base_name = smb_fname->base_name
162 NTSTATUS status;
164 * As we're calling getxattr directly here
165 * we need to use only the base_name, not
166 * the full name containing any stream name.
168 status = get_full_smb_filename(frame, &smb_fname_base, &path);
169 if (!NT_STATUS_IS_OK(status)) {
170 errno = map_errno_from_nt_status(status);
171 TALLOC_FREE(frame);
172 return -1;
175 /* This isn't quite right (calling getxattr not
176 * lgetxattr), but for the test purposes of this
177 * module (fake NT ACLs from windows clients), it is
178 * close enough. We removed the l*xattr functions
179 * because linux doesn't support using them, but we
180 * could fake them in xattr_tdb if we really wanted
181 * to. We ignore errors because the link might not point anywhere */
182 fake_acls_uid(handle, path, &smb_fname->st.st_ex_uid);
183 fake_acls_gid(handle, path, &smb_fname->st.st_ex_gid);
184 TALLOC_FREE(frame);
187 return ret;
190 static int fake_acls_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
192 int ret = -1;
194 ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
195 if (ret == 0) {
196 ret = fake_acls_fuid(handle, fsp, &sbuf->st_ex_uid);
197 if (ret != 0) {
198 return ret;
200 ret = fake_acls_fgid(handle, fsp, &sbuf->st_ex_gid);
201 if (ret != 0) {
202 return ret;
205 return ret;
208 static SMB_ACL_T fake_acls_blob2acl(DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
210 enum ndr_err_code ndr_err;
211 struct smb_acl_t *acl = talloc(mem_ctx, struct smb_acl_t);
212 if (!acl) {
213 errno = ENOMEM;
214 return NULL;
217 ndr_err = ndr_pull_struct_blob(blob, acl, acl,
218 (ndr_pull_flags_fn_t)ndr_pull_smb_acl_t);
220 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
221 DEBUG(0, ("ndr_pull_acl_t failed: %s\n",
222 ndr_errstr(ndr_err)));
223 TALLOC_FREE(acl);
224 return NULL;
226 return acl;
229 static DATA_BLOB fake_acls_acl2blob(TALLOC_CTX *mem_ctx, SMB_ACL_T acl)
231 enum ndr_err_code ndr_err;
232 DATA_BLOB blob;
233 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, acl,
234 (ndr_push_flags_fn_t)ndr_push_smb_acl_t);
236 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
237 DEBUG(0, ("ndr_push_acl_t failed: %s\n",
238 ndr_errstr(ndr_err)));
239 return data_blob_null;
241 return blob;
244 static SMB_ACL_T fake_acls_sys_acl_get_file(struct vfs_handle_struct *handle,
245 const char *path,
246 SMB_ACL_TYPE_T type,
247 TALLOC_CTX *mem_ctx)
249 DATA_BLOB blob = data_blob_null;
250 ssize_t length;
251 const char *name = NULL;
252 struct smb_acl_t *acl = NULL;
253 TALLOC_CTX *frame = talloc_stackframe();
254 switch (type) {
255 case SMB_ACL_TYPE_ACCESS:
256 name = FAKE_ACL_ACCESS_XATTR;
257 break;
258 case SMB_ACL_TYPE_DEFAULT:
259 name = FAKE_ACL_DEFAULT_XATTR;
260 break;
263 do {
264 blob.length += 1000;
265 blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
266 if (!blob.data) {
267 errno = ENOMEM;
268 TALLOC_FREE(frame);
269 return NULL;
271 length = SMB_VFS_NEXT_GETXATTR(handle, path, name, blob.data, blob.length);
272 blob.length = length;
273 } while (length == -1 && errno == ERANGE);
274 if (length == -1 && errno == ENOATTR) {
275 TALLOC_FREE(frame);
276 return NULL;
278 if (length != -1) {
279 acl = fake_acls_blob2acl(&blob, mem_ctx);
281 TALLOC_FREE(frame);
282 return acl;
285 static SMB_ACL_T fake_acls_sys_acl_get_fd(struct vfs_handle_struct *handle,
286 files_struct *fsp,
287 TALLOC_CTX *mem_ctx)
289 DATA_BLOB blob = data_blob_null;
290 ssize_t length;
291 const char *name = FAKE_ACL_ACCESS_XATTR;
292 struct smb_acl_t *acl = NULL;
293 TALLOC_CTX *frame = talloc_stackframe();
295 do {
296 blob.length += 1000;
297 blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
298 if (!blob.data) {
299 errno = ENOMEM;
300 TALLOC_FREE(frame);
301 return NULL;
303 length = SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, blob.data, blob.length);
304 blob.length = length;
305 } while (length == -1 && errno == ERANGE);
306 if (length == -1 && errno == ENOATTR) {
307 TALLOC_FREE(frame);
308 return NULL;
310 if (length != -1) {
311 acl = fake_acls_blob2acl(&blob, mem_ctx);
313 TALLOC_FREE(frame);
314 return acl;
318 static int fake_acls_sys_acl_set_file(vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
320 int ret;
321 const char *name = NULL;
322 TALLOC_CTX *frame = talloc_stackframe();
323 DATA_BLOB blob = fake_acls_acl2blob(frame, theacl);
324 if (!blob.data) {
325 DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n"));
326 TALLOC_FREE(frame);
327 errno = EINVAL;
328 return -1;
330 switch (acltype) {
331 case SMB_ACL_TYPE_ACCESS:
332 name = FAKE_ACL_ACCESS_XATTR;
333 break;
334 case SMB_ACL_TYPE_DEFAULT:
335 name = FAKE_ACL_DEFAULT_XATTR;
336 break;
338 ret = SMB_VFS_NEXT_SETXATTR(handle, path, name, blob.data, blob.length, 0);
339 TALLOC_FREE(frame);
340 return ret;
343 static int fake_acls_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, SMB_ACL_T theacl)
345 int ret;
346 const char *name = FAKE_ACL_ACCESS_XATTR;
347 TALLOC_CTX *frame = talloc_stackframe();
348 DATA_BLOB blob = fake_acls_acl2blob(frame, theacl);
349 if (!blob.data) {
350 DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n"));
351 TALLOC_FREE(frame);
352 errno = EINVAL;
353 return -1;
355 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, blob.data, blob.length, 0);
356 TALLOC_FREE(frame);
357 return ret;
360 static int fake_acls_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path)
362 int ret;
363 const char *name = FAKE_ACL_DEFAULT_XATTR;
364 TALLOC_CTX *frame = talloc_stackframe();
365 struct smb_filename *smb_fname;
367 smb_fname = synthetic_smb_fname(frame, path, NULL, NULL, 0);
368 if (smb_fname == NULL) {
369 TALLOC_FREE(frame);
370 errno = ENOMEM;
371 return -1;
374 ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
375 if (ret == -1) {
376 TALLOC_FREE(frame);
377 return -1;
380 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
381 errno = EINVAL;
382 TALLOC_FREE(frame);
383 return -1;
386 ret = SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
387 if (ret == -1 && errno == ENOATTR) {
388 ret = 0;
389 errno = 0;
392 TALLOC_FREE(frame);
393 return ret;
396 static int fake_acls_chown(vfs_handle_struct *handle,
397 const struct smb_filename *smb_fname,
398 uid_t uid,
399 gid_t gid)
401 int ret;
402 uint8_t id_buf[4];
403 if (uid != -1) {
404 SIVAL(id_buf, 0, uid);
405 ret = SMB_VFS_NEXT_SETXATTR(handle,
406 smb_fname->base_name,
407 FAKE_UID,
408 id_buf,
409 sizeof(id_buf),
411 if (ret != 0) {
412 return ret;
415 if (gid != -1) {
416 SIVAL(id_buf, 0, gid);
417 ret = SMB_VFS_NEXT_SETXATTR(handle,
418 smb_fname->base_name,
419 FAKE_GID,
420 id_buf,
421 sizeof(id_buf),
423 if (ret != 0) {
424 return ret;
427 return 0;
430 static int fake_acls_lchown(vfs_handle_struct *handle,
431 const struct smb_filename *smb_fname,
432 uid_t uid,
433 gid_t gid)
435 int ret;
436 uint8_t id_buf[4];
437 if (uid != -1) {
438 /* This isn't quite right (calling setxattr not
439 * lsetxattr), but for the test purposes of this
440 * module (fake NT ACLs from windows clients), it is
441 * close enough. We removed the l*xattr functions
442 * because linux doesn't support using them, but we
443 * could fake them in xattr_tdb if we really wanted
444 * to.
446 SIVAL(id_buf, 0, uid);
447 ret = SMB_VFS_NEXT_SETXATTR(handle,
448 smb_fname->base_name,
449 FAKE_UID,
450 id_buf,
451 sizeof(id_buf),
453 if (ret != 0) {
454 return ret;
457 if (gid != -1) {
458 SIVAL(id_buf, 0, gid);
459 ret = SMB_VFS_NEXT_SETXATTR(handle,
460 smb_fname->base_name,
461 FAKE_GID,
462 id_buf,
463 sizeof(id_buf),
465 if (ret != 0) {
466 return ret;
469 return 0;
472 static int fake_acls_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
474 int ret;
475 uint8_t id_buf[4];
476 if (uid != -1) {
477 SIVAL(id_buf, 0, uid);
478 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, FAKE_UID, id_buf, sizeof(id_buf), 0);
479 if (ret != 0) {
480 return ret;
483 if (gid != -1) {
484 SIVAL(id_buf, 0, gid);
485 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, FAKE_GID, id_buf, sizeof(id_buf), 0);
486 if (ret != 0) {
487 return ret;
490 return 0;
494 static struct vfs_fn_pointers vfs_fake_acls_fns = {
495 .stat_fn = fake_acls_stat,
496 .lstat_fn = fake_acls_lstat,
497 .fstat_fn = fake_acls_fstat,
498 .sys_acl_get_file_fn = fake_acls_sys_acl_get_file,
499 .sys_acl_get_fd_fn = fake_acls_sys_acl_get_fd,
500 .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
501 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
502 .sys_acl_set_file_fn = fake_acls_sys_acl_set_file,
503 .sys_acl_set_fd_fn = fake_acls_sys_acl_set_fd,
504 .sys_acl_delete_def_file_fn = fake_acls_sys_acl_delete_def_file,
505 .chown_fn = fake_acls_chown,
506 .lchown_fn = fake_acls_lchown,
507 .fchown_fn = fake_acls_fchown,
511 NTSTATUS vfs_fake_acls_init(void);
512 NTSTATUS vfs_fake_acls_init(void)
514 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "fake_acls",
515 &vfs_fake_acls_fns);