s3-rpc_client: move rpc_cli_transport structs and protos to rpc_transport.h
[Samba/gbeck.git] / source3 / modules / vfs_xattr_tdb.c
blob5b62565d62f58fd54a0674c685b4fbd36e9ff2f0
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 "system/filesys.h"
22 #include "smbd/smbd.h"
23 #include "librpc/gen_ndr/xattr.h"
24 #include "librpc/gen_ndr/ndr_xattr.h"
25 #include "../librpc/gen_ndr/ndr_netlogon.h"
26 #include "dbwrap.h"
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_VFS
32 * unmarshall tdb_xattrs
35 static NTSTATUS xattr_tdb_pull_attrs(TALLOC_CTX *mem_ctx,
36 const TDB_DATA *data,
37 struct tdb_xattrs **presult)
39 DATA_BLOB blob;
40 enum ndr_err_code ndr_err;
41 struct tdb_xattrs *result;
43 if (!(result = TALLOC_ZERO_P(mem_ctx, struct tdb_xattrs))) {
44 return NT_STATUS_NO_MEMORY;
47 if (data->dsize == 0) {
48 *presult = result;
49 return NT_STATUS_OK;
52 blob = data_blob_const(data->dptr, data->dsize);
54 ndr_err = ndr_pull_struct_blob(&blob, result, result,
55 (ndr_pull_flags_fn_t)ndr_pull_tdb_xattrs);
57 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
58 DEBUG(0, ("ndr_pull_tdb_xattrs failed: %s\n",
59 ndr_errstr(ndr_err)));
60 TALLOC_FREE(result);
61 return ndr_map_error2ntstatus(ndr_err);
64 *presult = result;
65 return NT_STATUS_OK;
69 * marshall tdb_xattrs
72 static NTSTATUS xattr_tdb_push_attrs(TALLOC_CTX *mem_ctx,
73 const struct tdb_xattrs *attribs,
74 TDB_DATA *data)
76 DATA_BLOB blob;
77 enum ndr_err_code ndr_err;
79 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, attribs,
80 (ndr_push_flags_fn_t)ndr_push_tdb_xattrs);
82 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
83 DEBUG(0, ("ndr_push_tdb_xattrs failed: %s\n",
84 ndr_errstr(ndr_err)));
85 return ndr_map_error2ntstatus(ndr_err);
88 *data = make_tdb_data(blob.data, blob.length);
89 return NT_STATUS_OK;
93 * Load tdb_xattrs for a file from the tdb
96 static NTSTATUS xattr_tdb_load_attrs(TALLOC_CTX *mem_ctx,
97 struct db_context *db_ctx,
98 const struct file_id *id,
99 struct tdb_xattrs **presult)
101 uint8 id_buf[16];
102 NTSTATUS status;
103 TDB_DATA data;
105 /* For backwards compatibility only store the dev/inode. */
106 push_file_id_16((char *)id_buf, id);
108 if (db_ctx->fetch(db_ctx, mem_ctx,
109 make_tdb_data(id_buf, sizeof(id_buf)),
110 &data) == -1) {
111 return NT_STATUS_INTERNAL_DB_CORRUPTION;
114 status = xattr_tdb_pull_attrs(mem_ctx, &data, presult);
115 TALLOC_FREE(data.dptr);
116 return status;
120 * fetch_lock the tdb_ea record for a file
123 static struct db_record *xattr_tdb_lock_attrs(TALLOC_CTX *mem_ctx,
124 struct db_context *db_ctx,
125 const struct file_id *id)
127 uint8 id_buf[16];
129 /* For backwards compatibility only store the dev/inode. */
130 push_file_id_16((char *)id_buf, id);
131 return db_ctx->fetch_locked(db_ctx, mem_ctx,
132 make_tdb_data(id_buf, sizeof(id_buf)));
136 * Save tdb_xattrs to a previously fetch_locked record
139 static NTSTATUS xattr_tdb_save_attrs(struct db_record *rec,
140 const struct tdb_xattrs *attribs)
142 TDB_DATA data = tdb_null;
143 NTSTATUS status;
145 status = xattr_tdb_push_attrs(talloc_tos(), attribs, &data);
147 if (!NT_STATUS_IS_OK(status)) {
148 DEBUG(0, ("xattr_tdb_push_attrs failed: %s\n",
149 nt_errstr(status)));
150 return status;
153 status = rec->store(rec, data, 0);
155 TALLOC_FREE(data.dptr);
157 return status;
161 * Worker routine for getxattr and fgetxattr
164 static ssize_t xattr_tdb_getattr(struct db_context *db_ctx,
165 const struct file_id *id,
166 const char *name, void *value, size_t size)
168 struct tdb_xattrs *attribs;
169 uint32_t i;
170 ssize_t result = -1;
171 NTSTATUS status;
173 DEBUG(10, ("xattr_tdb_getattr called for file %s, name %s\n",
174 file_id_string_tos(id), name));
176 status = xattr_tdb_load_attrs(talloc_tos(), db_ctx, id, &attribs);
178 if (!NT_STATUS_IS_OK(status)) {
179 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
180 nt_errstr(status)));
181 errno = EINVAL;
182 return -1;
185 for (i=0; i<attribs->num_eas; i++) {
186 if (strcmp(attribs->eas[i].name, name) == 0) {
187 break;
191 if (i == attribs->num_eas) {
192 errno = ENOATTR;
193 goto fail;
196 if (attribs->eas[i].value.length > size) {
197 errno = ERANGE;
198 goto fail;
201 memcpy(value, attribs->eas[i].value.data,
202 attribs->eas[i].value.length);
203 result = attribs->eas[i].value.length;
205 fail:
206 TALLOC_FREE(attribs);
207 return result;
210 static ssize_t xattr_tdb_getxattr(struct vfs_handle_struct *handle,
211 const char *path, const char *name,
212 void *value, size_t size)
214 SMB_STRUCT_STAT sbuf;
215 struct file_id id;
216 struct db_context *db;
218 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
220 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
221 return -1;
224 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
226 return xattr_tdb_getattr(db, &id, name, value, size);
229 static ssize_t xattr_tdb_fgetxattr(struct vfs_handle_struct *handle,
230 struct files_struct *fsp,
231 const char *name, void *value, size_t size)
233 SMB_STRUCT_STAT sbuf;
234 struct file_id id;
235 struct db_context *db;
237 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
239 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
240 return -1;
243 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
245 return xattr_tdb_getattr(db, &id, name, value, size);
249 * Worker routine for setxattr and fsetxattr
252 static int xattr_tdb_setattr(struct db_context *db_ctx,
253 const struct file_id *id, const char *name,
254 const void *value, size_t size, int flags)
256 NTSTATUS status;
257 struct db_record *rec;
258 struct tdb_xattrs *attribs;
259 uint32_t i;
261 DEBUG(10, ("xattr_tdb_setattr called for file %s, name %s\n",
262 file_id_string_tos(id), name));
264 rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
266 if (rec == NULL) {
267 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
268 errno = EINVAL;
269 return -1;
272 status = xattr_tdb_pull_attrs(rec, &rec->value, &attribs);
274 if (!NT_STATUS_IS_OK(status)) {
275 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
276 nt_errstr(status)));
277 TALLOC_FREE(rec);
278 return -1;
281 for (i=0; i<attribs->num_eas; i++) {
282 if (strcmp(attribs->eas[i].name, name) == 0) {
283 if (flags & XATTR_CREATE) {
284 TALLOC_FREE(rec);
285 errno = EEXIST;
286 return -1;
288 break;
292 if (i == attribs->num_eas) {
293 struct xattr_EA *tmp;
295 if (flags & XATTR_REPLACE) {
296 TALLOC_FREE(rec);
297 errno = ENOATTR;
298 return -1;
301 tmp = TALLOC_REALLOC_ARRAY(
302 attribs, attribs->eas, struct xattr_EA,
303 attribs->num_eas+ 1);
305 if (tmp == NULL) {
306 DEBUG(0, ("TALLOC_REALLOC_ARRAY failed\n"));
307 TALLOC_FREE(rec);
308 errno = ENOMEM;
309 return -1;
312 attribs->eas = tmp;
313 attribs->num_eas += 1;
316 attribs->eas[i].name = name;
317 attribs->eas[i].value.data = CONST_DISCARD(uint8 *, value);
318 attribs->eas[i].value.length = size;
320 status = xattr_tdb_save_attrs(rec, attribs);
322 TALLOC_FREE(rec);
324 if (!NT_STATUS_IS_OK(status)) {
325 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
326 return -1;
329 return 0;
332 static int xattr_tdb_setxattr(struct vfs_handle_struct *handle,
333 const char *path, const char *name,
334 const void *value, size_t size, int flags)
336 SMB_STRUCT_STAT sbuf;
337 struct file_id id;
338 struct db_context *db;
340 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
342 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
343 return -1;
346 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
348 return xattr_tdb_setattr(db, &id, name, value, size, flags);
351 static int xattr_tdb_fsetxattr(struct vfs_handle_struct *handle,
352 struct files_struct *fsp,
353 const char *name, const void *value,
354 size_t size, int flags)
356 SMB_STRUCT_STAT sbuf;
357 struct file_id id;
358 struct db_context *db;
360 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
362 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
363 return -1;
366 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
368 return xattr_tdb_setattr(db, &id, name, value, size, flags);
372 * Worker routine for listxattr and flistxattr
375 static ssize_t xattr_tdb_listattr(struct db_context *db_ctx,
376 const struct file_id *id, char *list,
377 size_t size)
379 NTSTATUS status;
380 struct tdb_xattrs *attribs;
381 uint32_t i;
382 size_t len = 0;
384 status = xattr_tdb_load_attrs(talloc_tos(), db_ctx, id, &attribs);
386 if (!NT_STATUS_IS_OK(status)) {
387 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
388 nt_errstr(status)));
389 errno = EINVAL;
390 return -1;
393 DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n",
394 attribs->num_eas));
396 for (i=0; i<attribs->num_eas; i++) {
397 size_t tmp;
399 DEBUG(10, ("xattr_tdb_listattr: xattrs[i].name: %s\n",
400 attribs->eas[i].name));
402 tmp = strlen(attribs->eas[i].name);
405 * Try to protect against overflow
408 if (len + (tmp+1) < len) {
409 TALLOC_FREE(attribs);
410 errno = EINVAL;
411 return -1;
415 * Take care of the terminating NULL
417 len += (tmp + 1);
420 if (len > size) {
421 TALLOC_FREE(attribs);
422 errno = ERANGE;
423 return -1;
426 len = 0;
428 for (i=0; i<attribs->num_eas; i++) {
429 strlcpy(list+len, attribs->eas[i].name,
430 size-len);
431 len += (strlen(attribs->eas[i].name) + 1);
434 TALLOC_FREE(attribs);
435 return len;
438 static ssize_t xattr_tdb_listxattr(struct vfs_handle_struct *handle,
439 const char *path, char *list, size_t size)
441 SMB_STRUCT_STAT sbuf;
442 struct file_id id;
443 struct db_context *db;
445 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
447 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
448 return -1;
451 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
453 return xattr_tdb_listattr(db, &id, list, size);
456 static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle,
457 struct files_struct *fsp, char *list,
458 size_t size)
460 SMB_STRUCT_STAT sbuf;
461 struct file_id id;
462 struct db_context *db;
464 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
466 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
467 return -1;
470 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
472 return xattr_tdb_listattr(db, &id, list, size);
476 * Worker routine for removexattr and fremovexattr
479 static int xattr_tdb_removeattr(struct db_context *db_ctx,
480 const struct file_id *id, const char *name)
482 NTSTATUS status;
483 struct db_record *rec;
484 struct tdb_xattrs *attribs;
485 uint32_t i;
487 rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
489 if (rec == NULL) {
490 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
491 errno = EINVAL;
492 return -1;
495 status = xattr_tdb_pull_attrs(rec, &rec->value, &attribs);
497 if (!NT_STATUS_IS_OK(status)) {
498 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
499 nt_errstr(status)));
500 TALLOC_FREE(rec);
501 return -1;
504 for (i=0; i<attribs->num_eas; i++) {
505 if (strcmp(attribs->eas[i].name, name) == 0) {
506 break;
510 if (i == attribs->num_eas) {
511 TALLOC_FREE(rec);
512 errno = ENOATTR;
513 return -1;
516 attribs->eas[i] =
517 attribs->eas[attribs->num_eas-1];
518 attribs->num_eas -= 1;
520 if (attribs->num_eas == 0) {
521 rec->delete_rec(rec);
522 TALLOC_FREE(rec);
523 return 0;
526 status = xattr_tdb_save_attrs(rec, attribs);
528 TALLOC_FREE(rec);
530 if (!NT_STATUS_IS_OK(status)) {
531 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
532 return -1;
535 return 0;
538 static int xattr_tdb_removexattr(struct vfs_handle_struct *handle,
539 const char *path, const char *name)
541 SMB_STRUCT_STAT sbuf;
542 struct file_id id;
543 struct db_context *db;
545 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
547 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
548 return -1;
551 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
553 return xattr_tdb_removeattr(db, &id, name);
556 static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle,
557 struct files_struct *fsp, const char *name)
559 SMB_STRUCT_STAT sbuf;
560 struct file_id id;
561 struct db_context *db;
563 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
565 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
566 return -1;
569 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
571 return xattr_tdb_removeattr(db, &id, name);
575 * Open the tdb file upon VFS_CONNECT
578 static bool xattr_tdb_init(int snum, struct db_context **p_db)
580 struct db_context *db;
581 const char *dbname;
582 char *def_dbname;
584 def_dbname = state_path("xattr.tdb");
585 if (def_dbname == NULL) {
586 errno = ENOSYS;
587 return false;
590 dbname = lp_parm_const_string(snum, "xattr_tdb", "file", def_dbname);
592 /* now we know dbname is not NULL */
594 become_root();
595 db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
596 unbecome_root();
598 if (db == NULL) {
599 #if defined(ENOTSUP)
600 errno = ENOTSUP;
601 #else
602 errno = ENOSYS;
603 #endif
604 TALLOC_FREE(def_dbname);
605 return false;
608 *p_db = db;
609 TALLOC_FREE(def_dbname);
610 return true;
614 * On unlink we need to delete the tdb record
616 static int xattr_tdb_unlink(vfs_handle_struct *handle,
617 const struct smb_filename *smb_fname)
619 struct smb_filename *smb_fname_tmp = NULL;
620 struct file_id id;
621 struct db_context *db;
622 struct db_record *rec;
623 NTSTATUS status;
624 int ret = -1;
625 bool remove_record = false;
627 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
629 status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
630 if (!NT_STATUS_IS_OK(status)) {
631 errno = map_errno_from_nt_status(status);
632 return -1;
635 if (lp_posix_pathnames()) {
636 ret = SMB_VFS_LSTAT(handle->conn, smb_fname_tmp);
637 } else {
638 ret = SMB_VFS_STAT(handle->conn, smb_fname_tmp);
640 if (ret == -1) {
641 goto out;
644 if (smb_fname_tmp->st.st_ex_nlink == 1) {
645 /* Only remove record on last link to file. */
646 remove_record = true;
649 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
651 if (ret == -1) {
652 goto out;
655 if (!remove_record) {
656 goto out;
659 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &smb_fname_tmp->st);
661 rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id);
664 * If rec == NULL there's not much we can do about it
667 if (rec != NULL) {
668 rec->delete_rec(rec);
669 TALLOC_FREE(rec);
672 out:
673 TALLOC_FREE(smb_fname_tmp);
674 return ret;
678 * On rmdir we need to delete the tdb record
680 static int xattr_tdb_rmdir(vfs_handle_struct *handle, const char *path)
682 SMB_STRUCT_STAT sbuf;
683 struct file_id id;
684 struct db_context *db;
685 struct db_record *rec;
686 int ret;
688 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
690 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
691 return -1;
694 ret = SMB_VFS_NEXT_RMDIR(handle, path);
696 if (ret == -1) {
697 return -1;
700 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
702 rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id);
705 * If rec == NULL there's not much we can do about it
708 if (rec != NULL) {
709 rec->delete_rec(rec);
710 TALLOC_FREE(rec);
713 return 0;
717 * Destructor for the VFS private data
720 static void close_xattr_db(void **data)
722 struct db_context **p_db = (struct db_context **)data;
723 TALLOC_FREE(*p_db);
726 static int xattr_tdb_connect(vfs_handle_struct *handle, const char *service,
727 const char *user)
729 char *sname = NULL;
730 int res, snum;
731 struct db_context *db;
733 res = SMB_VFS_NEXT_CONNECT(handle, service, user);
734 if (res < 0) {
735 return res;
738 snum = find_service(talloc_tos(), service, &sname);
739 if (snum == -1 || sname == NULL) {
741 * Should not happen, but we should not fail just *here*.
743 return 0;
746 if (!xattr_tdb_init(snum, &db)) {
747 DEBUG(5, ("Could not init xattr tdb\n"));
748 lp_do_parameter(snum, "ea support", "False");
749 return 0;
752 lp_do_parameter(snum, "ea support", "True");
754 SMB_VFS_HANDLE_SET_DATA(handle, db, close_xattr_db,
755 struct db_context, return -1);
757 return 0;
760 static struct vfs_fn_pointers vfs_xattr_tdb_fns = {
761 .getxattr = xattr_tdb_getxattr,
762 .fgetxattr = xattr_tdb_fgetxattr,
763 .setxattr = xattr_tdb_setxattr,
764 .fsetxattr = xattr_tdb_fsetxattr,
765 .listxattr = xattr_tdb_listxattr,
766 .flistxattr = xattr_tdb_flistxattr,
767 .removexattr = xattr_tdb_removexattr,
768 .fremovexattr = xattr_tdb_fremovexattr,
769 .unlink = xattr_tdb_unlink,
770 .rmdir = xattr_tdb_rmdir,
771 .connect_fn = xattr_tdb_connect,
774 NTSTATUS vfs_xattr_tdb_init(void);
775 NTSTATUS vfs_xattr_tdb_init(void)
777 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "xattr_tdb",
778 &vfs_xattr_tdb_fns);