Fix valgrind "uninitialized read" error on "info" when returning !NT_STATUS_OK.
[Samba.git] / source3 / modules / vfs_xattr_tdb.c
blob28b21b6bf6964071a4439208c17ee06bc86bc2ff
1 /*
2 * Store posix-level xattrs in a tdb
4 * Copyright (C) Volker Lendecke, 2007
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "librpc/gen_ndr/xattr.h"
22 #include "librpc/gen_ndr/ndr_xattr.h"
23 #include "../librpc/gen_ndr/ndr_netlogon.h"
25 #undef DBGC_CLASS
26 #define DBGC_CLASS DBGC_VFS
29 * unmarshall tdb_xattrs
32 static NTSTATUS xattr_tdb_pull_attrs(TALLOC_CTX *mem_ctx,
33 const TDB_DATA *data,
34 struct tdb_xattrs **presult)
36 DATA_BLOB blob;
37 enum ndr_err_code ndr_err;
38 struct tdb_xattrs *result;
40 if (!(result = TALLOC_ZERO_P(mem_ctx, struct tdb_xattrs))) {
41 return NT_STATUS_NO_MEMORY;
44 if (data->dsize == 0) {
45 *presult = result;
46 return NT_STATUS_OK;
49 blob = data_blob_const(data->dptr, data->dsize);
51 ndr_err = ndr_pull_struct_blob(&blob, result, result,
52 (ndr_pull_flags_fn_t)ndr_pull_tdb_xattrs);
54 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
55 DEBUG(0, ("ndr_pull_tdb_xattrs failed: %s\n",
56 ndr_errstr(ndr_err)));
57 TALLOC_FREE(result);
58 return ndr_map_error2ntstatus(ndr_err);;
61 *presult = result;
62 return NT_STATUS_OK;
66 * marshall tdb_xattrs
69 static NTSTATUS xattr_tdb_push_attrs(TALLOC_CTX *mem_ctx,
70 const struct tdb_xattrs *attribs,
71 TDB_DATA *data)
73 DATA_BLOB blob;
74 enum ndr_err_code ndr_err;
76 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, attribs,
77 (ndr_push_flags_fn_t)ndr_push_tdb_xattrs);
79 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
80 DEBUG(0, ("ndr_push_tdb_xattrs failed: %s\n",
81 ndr_errstr(ndr_err)));
82 return ndr_map_error2ntstatus(ndr_err);;
85 *data = make_tdb_data(blob.data, blob.length);
86 return NT_STATUS_OK;
90 * Load tdb_xattrs for a file from the tdb
93 static NTSTATUS xattr_tdb_load_attrs(TALLOC_CTX *mem_ctx,
94 struct db_context *db_ctx,
95 const struct file_id *id,
96 struct tdb_xattrs **presult)
98 uint8 id_buf[16];
99 NTSTATUS status;
100 TDB_DATA data;
102 /* For backwards compatibility only store the dev/inode. */
103 push_file_id_16((char *)id_buf, id);
105 if (db_ctx->fetch(db_ctx, mem_ctx,
106 make_tdb_data(id_buf, sizeof(id_buf)),
107 &data) == -1) {
108 return NT_STATUS_INTERNAL_DB_CORRUPTION;
111 status = xattr_tdb_pull_attrs(mem_ctx, &data, presult);
112 TALLOC_FREE(data.dptr);
113 return status;
117 * fetch_lock the tdb_ea record for a file
120 static struct db_record *xattr_tdb_lock_attrs(TALLOC_CTX *mem_ctx,
121 struct db_context *db_ctx,
122 const struct file_id *id)
124 uint8 id_buf[16];
126 /* For backwards compatibility only store the dev/inode. */
127 push_file_id_16((char *)id_buf, id);
128 return db_ctx->fetch_locked(db_ctx, mem_ctx,
129 make_tdb_data(id_buf, sizeof(id_buf)));
133 * Save tdb_xattrs to a previously fetch_locked record
136 static NTSTATUS xattr_tdb_save_attrs(struct db_record *rec,
137 const struct tdb_xattrs *attribs)
139 TDB_DATA data = tdb_null;
140 NTSTATUS status;
142 status = xattr_tdb_push_attrs(talloc_tos(), attribs, &data);
144 if (!NT_STATUS_IS_OK(status)) {
145 DEBUG(0, ("xattr_tdb_push_attrs failed: %s\n",
146 nt_errstr(status)));
147 return status;
150 status = rec->store(rec, data, 0);
152 TALLOC_FREE(data.dptr);
154 return status;
158 * Worker routine for getxattr and fgetxattr
161 static ssize_t xattr_tdb_getattr(struct db_context *db_ctx,
162 const struct file_id *id,
163 const char *name, void *value, size_t size)
165 struct tdb_xattrs *attribs;
166 uint32_t i;
167 ssize_t result = -1;
168 NTSTATUS status;
170 DEBUG(10, ("xattr_tdb_getattr called for file %s, name %s\n",
171 file_id_string_tos(id), name));
173 status = xattr_tdb_load_attrs(talloc_tos(), db_ctx, id, &attribs);
175 if (!NT_STATUS_IS_OK(status)) {
176 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
177 nt_errstr(status)));
178 errno = EINVAL;
179 return -1;
182 for (i=0; i<attribs->num_eas; i++) {
183 if (strcmp(attribs->eas[i].name, name) == 0) {
184 break;
188 if (i == attribs->num_eas) {
189 errno = ENOATTR;
190 goto fail;
193 if (attribs->eas[i].value.length > size) {
194 errno = ERANGE;
195 goto fail;
198 memcpy(value, attribs->eas[i].value.data,
199 attribs->eas[i].value.length);
200 result = attribs->eas[i].value.length;
202 fail:
203 TALLOC_FREE(attribs);
204 return result;
207 static ssize_t xattr_tdb_getxattr(struct vfs_handle_struct *handle,
208 const char *path, const char *name,
209 void *value, size_t size)
211 SMB_STRUCT_STAT sbuf;
212 struct file_id id;
213 struct db_context *db;
215 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
217 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
218 return -1;
221 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
223 return xattr_tdb_getattr(db, &id, name, value, size);
226 static ssize_t xattr_tdb_fgetxattr(struct vfs_handle_struct *handle,
227 struct files_struct *fsp,
228 const char *name, void *value, size_t size)
230 SMB_STRUCT_STAT sbuf;
231 struct file_id id;
232 struct db_context *db;
234 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
236 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
237 return -1;
240 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
242 return xattr_tdb_getattr(db, &id, name, value, size);
246 * Worker routine for setxattr and fsetxattr
249 static int xattr_tdb_setattr(struct db_context *db_ctx,
250 const struct file_id *id, const char *name,
251 const void *value, size_t size, int flags)
253 NTSTATUS status;
254 struct db_record *rec;
255 struct tdb_xattrs *attribs;
256 uint32_t i;
258 DEBUG(10, ("xattr_tdb_setattr called for file %s, name %s\n",
259 file_id_string_tos(id), name));
261 rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
263 if (rec == NULL) {
264 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
265 errno = EINVAL;
266 return -1;
269 status = xattr_tdb_pull_attrs(rec, &rec->value, &attribs);
271 if (!NT_STATUS_IS_OK(status)) {
272 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
273 nt_errstr(status)));
274 TALLOC_FREE(rec);
275 return -1;
278 for (i=0; i<attribs->num_eas; i++) {
279 if (strcmp(attribs->eas[i].name, name) == 0) {
280 if (flags & XATTR_CREATE) {
281 TALLOC_FREE(rec);
282 errno = EEXIST;
283 return -1;
285 break;
289 if (i == attribs->num_eas) {
290 struct xattr_EA *tmp;
292 if (flags & XATTR_REPLACE) {
293 TALLOC_FREE(rec);
294 errno = ENOATTR;
295 return -1;
298 tmp = TALLOC_REALLOC_ARRAY(
299 attribs, attribs->eas, struct xattr_EA,
300 attribs->num_eas+ 1);
302 if (tmp == NULL) {
303 DEBUG(0, ("TALLOC_REALLOC_ARRAY failed\n"));
304 TALLOC_FREE(rec);
305 errno = ENOMEM;
306 return -1;
309 attribs->eas = tmp;
310 attribs->num_eas += 1;
313 attribs->eas[i].name = name;
314 attribs->eas[i].value.data = CONST_DISCARD(uint8 *, value);
315 attribs->eas[i].value.length = size;
317 status = xattr_tdb_save_attrs(rec, attribs);
319 TALLOC_FREE(rec);
321 if (!NT_STATUS_IS_OK(status)) {
322 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
323 return -1;
326 return 0;
329 static int xattr_tdb_setxattr(struct vfs_handle_struct *handle,
330 const char *path, const char *name,
331 const void *value, size_t size, int flags)
333 SMB_STRUCT_STAT sbuf;
334 struct file_id id;
335 struct db_context *db;
337 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
339 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
340 return -1;
343 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
345 return xattr_tdb_setattr(db, &id, name, value, size, flags);
348 static int xattr_tdb_fsetxattr(struct vfs_handle_struct *handle,
349 struct files_struct *fsp,
350 const char *name, const void *value,
351 size_t size, int flags)
353 SMB_STRUCT_STAT sbuf;
354 struct file_id id;
355 struct db_context *db;
357 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
359 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
360 return -1;
363 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
365 return xattr_tdb_setattr(db, &id, name, value, size, flags);
369 * Worker routine for listxattr and flistxattr
372 static ssize_t xattr_tdb_listattr(struct db_context *db_ctx,
373 const struct file_id *id, char *list,
374 size_t size)
376 NTSTATUS status;
377 struct tdb_xattrs *attribs;
378 uint32_t i;
379 size_t len = 0;
381 status = xattr_tdb_load_attrs(talloc_tos(), db_ctx, id, &attribs);
383 if (!NT_STATUS_IS_OK(status)) {
384 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
385 nt_errstr(status)));
386 errno = EINVAL;
387 return -1;
390 DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n",
391 attribs->num_eas));
393 for (i=0; i<attribs->num_eas; i++) {
394 size_t tmp;
396 DEBUG(10, ("xattr_tdb_listattr: xattrs[i].name: %s\n",
397 attribs->eas[i].name));
399 tmp = strlen(attribs->eas[i].name);
402 * Try to protect against overflow
405 if (len + (tmp+1) < len) {
406 TALLOC_FREE(attribs);
407 errno = EINVAL;
408 return -1;
412 * Take care of the terminating NULL
414 len += (tmp + 1);
417 if (len > size) {
418 TALLOC_FREE(attribs);
419 errno = ERANGE;
420 return -1;
423 len = 0;
425 for (i=0; i<attribs->num_eas; i++) {
426 strlcpy(list+len, attribs->eas[i].name,
427 size-len);
428 len += (strlen(attribs->eas[i].name) + 1);
431 TALLOC_FREE(attribs);
432 return len;
435 static ssize_t xattr_tdb_listxattr(struct vfs_handle_struct *handle,
436 const char *path, char *list, size_t size)
438 SMB_STRUCT_STAT sbuf;
439 struct file_id id;
440 struct db_context *db;
442 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
444 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
445 return -1;
448 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
450 return xattr_tdb_listattr(db, &id, list, size);
453 static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle,
454 struct files_struct *fsp, char *list,
455 size_t size)
457 SMB_STRUCT_STAT sbuf;
458 struct file_id id;
459 struct db_context *db;
461 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
463 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
464 return -1;
467 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
469 return xattr_tdb_listattr(db, &id, list, size);
473 * Worker routine for removexattr and fremovexattr
476 static int xattr_tdb_removeattr(struct db_context *db_ctx,
477 const struct file_id *id, const char *name)
479 NTSTATUS status;
480 struct db_record *rec;
481 struct tdb_xattrs *attribs;
482 uint32_t i;
484 rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
486 if (rec == NULL) {
487 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
488 errno = EINVAL;
489 return -1;
492 status = xattr_tdb_pull_attrs(rec, &rec->value, &attribs);
494 if (!NT_STATUS_IS_OK(status)) {
495 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
496 nt_errstr(status)));
497 TALLOC_FREE(rec);
498 return -1;
501 for (i=0; i<attribs->num_eas; i++) {
502 if (strcmp(attribs->eas[i].name, name) == 0) {
503 break;
507 if (i == attribs->num_eas) {
508 TALLOC_FREE(rec);
509 errno = ENOATTR;
510 return -1;
513 attribs->eas[i] =
514 attribs->eas[attribs->num_eas-1];
515 attribs->num_eas -= 1;
517 if (attribs->num_eas == 0) {
518 rec->delete_rec(rec);
519 TALLOC_FREE(rec);
520 return 0;
523 status = xattr_tdb_save_attrs(rec, attribs);
525 TALLOC_FREE(rec);
527 if (!NT_STATUS_IS_OK(status)) {
528 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
529 return -1;
532 return 0;
535 static int xattr_tdb_removexattr(struct vfs_handle_struct *handle,
536 const char *path, const char *name)
538 SMB_STRUCT_STAT sbuf;
539 struct file_id id;
540 struct db_context *db;
542 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
544 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
545 return -1;
548 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
550 return xattr_tdb_removeattr(db, &id, name);
553 static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle,
554 struct files_struct *fsp, const char *name)
556 SMB_STRUCT_STAT sbuf;
557 struct file_id id;
558 struct db_context *db;
560 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
562 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
563 return -1;
566 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
568 return xattr_tdb_removeattr(db, &id, name);
572 * Open the tdb file upon VFS_CONNECT
575 static bool xattr_tdb_init(int snum, struct db_context **p_db)
577 struct db_context *db;
578 const char *dbname;
579 char *def_dbname;
581 def_dbname = state_path("xattr.tdb");
582 if (def_dbname == NULL) {
583 errno = ENOSYS;
584 return false;
587 dbname = lp_parm_const_string(snum, "xattr_tdb", "file", def_dbname);
589 /* now we know dbname is not NULL */
591 become_root();
592 db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
593 unbecome_root();
595 if (db == NULL) {
596 #if defined(ENOTSUP)
597 errno = ENOTSUP;
598 #else
599 errno = ENOSYS;
600 #endif
601 TALLOC_FREE(def_dbname);
602 return false;
605 *p_db = db;
606 TALLOC_FREE(def_dbname);
607 return true;
611 * On unlink we need to delete the tdb record
613 static int xattr_tdb_unlink(vfs_handle_struct *handle,
614 const struct smb_filename *smb_fname)
616 struct smb_filename *smb_fname_tmp = NULL;
617 struct file_id id;
618 struct db_context *db;
619 struct db_record *rec;
620 NTSTATUS status;
621 int ret = -1;
622 bool remove_record = false;
624 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
626 status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
627 if (!NT_STATUS_IS_OK(status)) {
628 errno = map_errno_from_nt_status(status);
629 return -1;
632 if (lp_posix_pathnames()) {
633 ret = SMB_VFS_LSTAT(handle->conn, smb_fname_tmp);
634 } else {
635 ret = SMB_VFS_STAT(handle->conn, smb_fname_tmp);
637 if (ret == -1) {
638 goto out;
641 if (smb_fname_tmp->st.st_ex_nlink == 1) {
642 /* Only remove record on last link to file. */
643 remove_record = true;
646 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
648 if (ret == -1) {
649 goto out;
652 if (!remove_record) {
653 goto out;
656 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &smb_fname_tmp->st);
658 rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id);
661 * If rec == NULL there's not much we can do about it
664 if (rec != NULL) {
665 rec->delete_rec(rec);
666 TALLOC_FREE(rec);
669 out:
670 TALLOC_FREE(smb_fname_tmp);
671 return ret;
675 * On rmdir we need to delete the tdb record
677 static int xattr_tdb_rmdir(vfs_handle_struct *handle, const char *path)
679 SMB_STRUCT_STAT sbuf;
680 struct file_id id;
681 struct db_context *db;
682 struct db_record *rec;
683 int ret;
685 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
687 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
688 return -1;
691 ret = SMB_VFS_NEXT_RMDIR(handle, path);
693 if (ret == -1) {
694 return -1;
697 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
699 rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id);
702 * If rec == NULL there's not much we can do about it
705 if (rec != NULL) {
706 rec->delete_rec(rec);
707 TALLOC_FREE(rec);
710 return 0;
714 * Destructor for the VFS private data
717 static void close_xattr_db(void **data)
719 struct db_context **p_db = (struct db_context **)data;
720 TALLOC_FREE(*p_db);
723 static int xattr_tdb_connect(vfs_handle_struct *handle, const char *service,
724 const char *user)
726 fstring sname;
727 int res, snum;
728 struct db_context *db;
730 res = SMB_VFS_NEXT_CONNECT(handle, service, user);
731 if (res < 0) {
732 return res;
735 fstrcpy(sname, service);
736 snum = find_service(sname);
737 if (snum == -1) {
739 * Should not happen, but we should not fail just *here*.
741 return 0;
744 if (!xattr_tdb_init(snum, &db)) {
745 DEBUG(5, ("Could not init xattr tdb\n"));
746 lp_do_parameter(snum, "ea support", "False");
747 return 0;
750 lp_do_parameter(snum, "ea support", "True");
752 SMB_VFS_HANDLE_SET_DATA(handle, db, close_xattr_db,
753 struct db_context, return -1);
755 return 0;
758 static struct vfs_fn_pointers vfs_xattr_tdb_fns = {
759 .getxattr = xattr_tdb_getxattr,
760 .fgetxattr = xattr_tdb_fgetxattr,
761 .setxattr = xattr_tdb_setxattr,
762 .fsetxattr = xattr_tdb_fsetxattr,
763 .listxattr = xattr_tdb_listxattr,
764 .flistxattr = xattr_tdb_flistxattr,
765 .removexattr = xattr_tdb_removexattr,
766 .fremovexattr = xattr_tdb_fremovexattr,
767 .unlink = xattr_tdb_unlink,
768 .rmdir = xattr_tdb_rmdir,
769 .connect_fn = xattr_tdb_connect,
772 NTSTATUS vfs_xattr_tdb_init(void);
773 NTSTATUS vfs_xattr_tdb_init(void)
775 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "xattr_tdb",
776 &vfs_xattr_tdb_fns);