libcli/smb: fix padding in smb2_create_blob*
[Samba/gebeck_regimport.git] / source3 / modules / vfs_fake_acls.c
blob258cb197c0b9dd766824029f4ad5ed5af8a55878
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_lstat(vfs_handle_struct *handle,
143 struct smb_filename *smb_fname)
145 int ret = -1;
147 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
148 if (ret == 0) {
149 TALLOC_CTX *frame = talloc_stackframe();
150 char *path;
151 NTSTATUS status;
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);
155 TALLOC_FREE(frame);
156 return -1;
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);
168 TALLOC_FREE(frame);
171 return ret;
174 static int fake_acls_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
176 int ret = -1;
178 ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
179 if (ret == 0) {
180 ret = fake_acls_fuid(handle, fsp, &sbuf->st_ex_uid);
181 if (ret != 0) {
182 return ret;
184 ret = fake_acls_fgid(handle, fsp, &sbuf->st_ex_gid);
185 if (ret != 0) {
186 return ret;
189 return ret;
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);
197 if (!acl) {
198 errno = ENOMEM;
199 return NULL;
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)));
208 TALLOC_FREE(acl);
209 return NULL;
211 return acl;
214 static DATA_BLOB fake_acls_acl2blob(TALLOC_CTX *mem_ctx, SMB_ACL_T acl)
216 enum ndr_err_code ndr_err;
217 DATA_BLOB blob;
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;
226 return blob;
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;
232 ssize_t length;
233 const char *name = NULL;
234 struct smb_acl_t *acl = NULL;
235 TALLOC_CTX *frame = talloc_stackframe();
236 switch (type) {
237 case SMB_ACL_TYPE_ACCESS:
238 name = FAKE_ACL_ACCESS_XATTR;
239 break;
240 case SMB_ACL_TYPE_DEFAULT:
241 name = FAKE_ACL_DEFAULT_XATTR;
242 break;
245 do {
246 blob.length += 1000;
247 blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
248 if (!blob.data) {
249 errno = ENOMEM;
250 TALLOC_FREE(frame);
251 return NULL;
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) {
257 TALLOC_FREE(frame);
258 return NULL;
260 if (length != -1) {
261 acl = fake_acls_blob2acl(&blob);
263 TALLOC_FREE(frame);
264 return acl;
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;
270 ssize_t length;
271 const char *name = FAKE_ACL_ACCESS_XATTR;
272 struct smb_acl_t *acl;
273 TALLOC_CTX *frame = talloc_stackframe();
275 do {
276 blob.length += 1000;
277 blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
278 if (!blob.data) {
279 errno = ENOMEM;
280 TALLOC_FREE(frame);
281 return NULL;
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) {
287 TALLOC_FREE(frame);
288 return NULL;
290 if (length != -1) {
291 acl = fake_acls_blob2acl(&blob);
293 TALLOC_FREE(frame);
294 return acl;
298 static int fake_acls_sys_acl_blob_get_file(struct vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T type, TALLOC_CTX *mem_ctx,
299 char **blob_description, DATA_BLOB *blob)
301 ssize_t length;
302 const char *name = NULL;
303 switch (type) {
304 case SMB_ACL_TYPE_ACCESS:
305 name = FAKE_ACL_ACCESS_XATTR;
306 break;
307 case SMB_ACL_TYPE_DEFAULT:
308 name = FAKE_ACL_DEFAULT_XATTR;
309 break;
312 *blob_description = talloc_strdup(mem_ctx, "fake_acls");
313 if (!*blob_description) {
314 errno = ENOMEM;
315 return -1;
318 *blob = data_blob_null;
319 do {
320 blob->length += 1000;
321 blob->data = talloc_realloc(mem_ctx, blob->data, uint8_t, blob->length);
322 if (!blob->data) {
323 errno = ENOMEM;
324 return -1;
326 length = SMB_VFS_NEXT_GETXATTR(handle, path, name, blob->data, blob->length);
327 blob->length = length;
328 } while (length == -1 && errno == ERANGE);
329 if (length == -1) {
330 return -1;
332 return 0;
335 static int fake_acls_sys_acl_blob_get_fd(struct vfs_handle_struct *handle, files_struct *fsp, TALLOC_CTX *mem_ctx,
336 char **blob_description, DATA_BLOB *blob)
338 ssize_t length;
339 const char *name = FAKE_ACL_ACCESS_XATTR;
341 *blob_description = talloc_strdup(mem_ctx, "fake_acls");
342 if (!*blob_description) {
343 errno = ENOMEM;
344 return -1;
346 *blob = data_blob_null;
347 do {
348 blob->length += 1000;
349 blob->data = talloc_realloc(mem_ctx, blob->data, uint8_t, blob->length);
350 if (!blob->data) {
351 errno = ENOMEM;
352 return -1;
354 length = SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, blob->data, blob->length);
355 blob->length = length;
356 } while (length == -1 && errno == ERANGE);
357 if (length == -1) {
358 return -1;
360 return 0;
363 static int fake_acls_sys_acl_set_file(vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
365 int ret;
366 const char *name = NULL;
367 TALLOC_CTX *frame = talloc_stackframe();
368 DATA_BLOB blob = fake_acls_acl2blob(frame, theacl);
369 if (!blob.data) {
370 DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n"));
371 TALLOC_FREE(frame);
372 errno = EINVAL;
373 return -1;
375 switch (acltype) {
376 case SMB_ACL_TYPE_ACCESS:
377 name = FAKE_ACL_ACCESS_XATTR;
378 break;
379 case SMB_ACL_TYPE_DEFAULT:
380 name = FAKE_ACL_DEFAULT_XATTR;
381 break;
383 ret = SMB_VFS_NEXT_SETXATTR(handle, path, name, blob.data, blob.length, 0);
384 TALLOC_FREE(frame);
385 return ret;
388 static int fake_acls_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, SMB_ACL_T theacl)
390 int ret;
391 const char *name = FAKE_ACL_ACCESS_XATTR;
392 TALLOC_CTX *frame = talloc_stackframe();
393 DATA_BLOB blob = fake_acls_acl2blob(frame, theacl);
394 if (!blob.data) {
395 DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n"));
396 TALLOC_FREE(frame);
397 errno = EINVAL;
398 return -1;
400 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, blob.data, blob.length, 0);
401 TALLOC_FREE(frame);
402 return ret;
405 static int fake_acls_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path)
407 int ret;
408 const char *name = FAKE_ACL_DEFAULT_XATTR;
409 TALLOC_CTX *frame = talloc_stackframe();
410 struct smb_filename *smb_fname = NULL;
411 NTSTATUS status = create_synthetic_smb_fname_split(frame, path, NULL,
412 &smb_fname);
413 if (!NT_STATUS_IS_OK(status)) {
414 errno = map_errno_from_nt_status(status);
415 TALLOC_FREE(frame);
416 return -1;
419 ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
420 if (ret == -1) {
421 TALLOC_FREE(frame);
422 return -1;
425 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
426 errno = EINVAL;
427 TALLOC_FREE(frame);
428 return -1;
431 ret = SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
432 if (ret == -1 && errno == ENOATTR) {
433 ret = 0;
434 errno = 0;
437 TALLOC_FREE(frame);
438 return ret;
441 static int fake_acls_chown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
443 int ret;
444 uint8_t id_buf[4];
445 if (uid != -1) {
446 SIVAL(id_buf, 0, uid);
447 ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_UID, id_buf, sizeof(id_buf), 0);
448 if (ret != 0) {
449 return ret;
452 if (gid != -1) {
453 SIVAL(id_buf, 0, gid);
454 ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_GID, id_buf, sizeof(id_buf), 0);
455 if (ret != 0) {
456 return ret;
459 return 0;
462 static int fake_acls_lchown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
464 int ret;
465 uint8_t id_buf[4];
466 if (uid != -1) {
467 /* This isn't quite right (calling setxattr not
468 * lsetxattr), but for the test purposes of this
469 * module (fake NT ACLs from windows clients), it is
470 * close enough. We removed the l*xattr functions
471 * because linux doesn't support using them, but we
472 * could fake them in xattr_tdb if we really wanted
473 * to.
475 SIVAL(id_buf, 0, uid);
476 ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_UID, id_buf, sizeof(id_buf), 0);
477 if (ret != 0) {
478 return ret;
481 if (gid != -1) {
482 SIVAL(id_buf, 0, gid);
483 ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_GID, id_buf, sizeof(id_buf), 0);
484 if (ret != 0) {
485 return ret;
488 return 0;
491 static int fake_acls_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
493 int ret;
494 uint8_t id_buf[4];
495 if (uid != -1) {
496 SIVAL(id_buf, 0, uid);
497 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, FAKE_UID, id_buf, sizeof(id_buf), 0);
498 if (ret != 0) {
499 return ret;
502 if (gid != -1) {
503 SIVAL(id_buf, 0, gid);
504 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, FAKE_GID, id_buf, sizeof(id_buf), 0);
505 if (ret != 0) {
506 return ret;
509 return 0;
513 static struct vfs_fn_pointers vfs_fake_acls_fns = {
514 .stat_fn = fake_acls_stat,
515 .lstat_fn = fake_acls_lstat,
516 .fstat_fn = fake_acls_fstat,
517 .sys_acl_get_file_fn = fake_acls_sys_acl_get_file,
518 .sys_acl_get_fd_fn = fake_acls_sys_acl_get_fd,
519 .sys_acl_blob_get_file_fn = fake_acls_sys_acl_blob_get_file,
520 .sys_acl_blob_get_fd_fn = fake_acls_sys_acl_blob_get_fd,
521 .sys_acl_set_file_fn = fake_acls_sys_acl_set_file,
522 .sys_acl_set_fd_fn = fake_acls_sys_acl_set_fd,
523 .sys_acl_delete_def_file_fn = fake_acls_sys_acl_delete_def_file,
524 .chown_fn = fake_acls_chown,
525 .lchown_fn = fake_acls_lchown,
526 .fchown_fn = fake_acls_fchown,
530 NTSTATUS vfs_fake_acls_init(void);
531 NTSTATUS vfs_fake_acls_init(void)
533 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "fake_acls",
534 &vfs_fake_acls_fns);