s3-utils/net_rpc_printer.c: print more info on write error
[Samba/gebeck_regimport.git] / source3 / modules / vfs_xattr_tdb.c
blob40ccf06dd951e39943872e8a775b8579017b5baa
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"
27 #include "util_tdb.h"
29 #undef DBGC_CLASS
30 #define DBGC_CLASS DBGC_VFS
33 * unmarshall tdb_xattrs
36 static NTSTATUS xattr_tdb_pull_attrs(TALLOC_CTX *mem_ctx,
37 const TDB_DATA *data,
38 struct tdb_xattrs **presult)
40 DATA_BLOB blob;
41 enum ndr_err_code ndr_err;
42 struct tdb_xattrs *result;
44 if (!(result = talloc_zero(mem_ctx, struct tdb_xattrs))) {
45 return NT_STATUS_NO_MEMORY;
48 if (data->dsize == 0) {
49 *presult = result;
50 return NT_STATUS_OK;
53 blob = data_blob_const(data->dptr, data->dsize);
55 ndr_err = ndr_pull_struct_blob(&blob, result, result,
56 (ndr_pull_flags_fn_t)ndr_pull_tdb_xattrs);
58 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
59 DEBUG(0, ("ndr_pull_tdb_xattrs failed: %s\n",
60 ndr_errstr(ndr_err)));
61 TALLOC_FREE(result);
62 return ndr_map_error2ntstatus(ndr_err);
65 *presult = result;
66 return NT_STATUS_OK;
70 * marshall tdb_xattrs
73 static NTSTATUS xattr_tdb_push_attrs(TALLOC_CTX *mem_ctx,
74 const struct tdb_xattrs *attribs,
75 TDB_DATA *data)
77 DATA_BLOB blob;
78 enum ndr_err_code ndr_err;
80 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, attribs,
81 (ndr_push_flags_fn_t)ndr_push_tdb_xattrs);
83 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
84 DEBUG(0, ("ndr_push_tdb_xattrs failed: %s\n",
85 ndr_errstr(ndr_err)));
86 return ndr_map_error2ntstatus(ndr_err);
89 *data = make_tdb_data(blob.data, blob.length);
90 return NT_STATUS_OK;
94 * Load tdb_xattrs for a file from the tdb
97 static NTSTATUS xattr_tdb_load_attrs(TALLOC_CTX *mem_ctx,
98 struct db_context *db_ctx,
99 const struct file_id *id,
100 struct tdb_xattrs **presult)
102 uint8 id_buf[16];
103 NTSTATUS status;
104 TDB_DATA data;
106 /* For backwards compatibility only store the dev/inode. */
107 push_file_id_16((char *)id_buf, id);
109 if (db_ctx->fetch(db_ctx, mem_ctx,
110 make_tdb_data(id_buf, sizeof(id_buf)),
111 &data) != 0) {
112 return NT_STATUS_INTERNAL_DB_CORRUPTION;
115 status = xattr_tdb_pull_attrs(mem_ctx, &data, presult);
116 TALLOC_FREE(data.dptr);
117 return status;
121 * fetch_lock the tdb_ea record for a file
124 static struct db_record *xattr_tdb_lock_attrs(TALLOC_CTX *mem_ctx,
125 struct db_context *db_ctx,
126 const struct file_id *id)
128 uint8 id_buf[16];
130 /* For backwards compatibility only store the dev/inode. */
131 push_file_id_16((char *)id_buf, id);
132 return db_ctx->fetch_locked(db_ctx, mem_ctx,
133 make_tdb_data(id_buf, sizeof(id_buf)));
137 * Save tdb_xattrs to a previously fetch_locked record
140 static NTSTATUS xattr_tdb_save_attrs(struct db_record *rec,
141 const struct tdb_xattrs *attribs)
143 TDB_DATA data = tdb_null;
144 NTSTATUS status;
146 status = xattr_tdb_push_attrs(talloc_tos(), attribs, &data);
148 if (!NT_STATUS_IS_OK(status)) {
149 DEBUG(0, ("xattr_tdb_push_attrs failed: %s\n",
150 nt_errstr(status)));
151 return status;
154 status = rec->store(rec, data, 0);
156 TALLOC_FREE(data.dptr);
158 return status;
162 * Worker routine for getxattr and fgetxattr
165 static ssize_t xattr_tdb_getattr(struct db_context *db_ctx,
166 const struct file_id *id,
167 const char *name, void *value, size_t size)
169 struct tdb_xattrs *attribs;
170 uint32_t i;
171 ssize_t result = -1;
172 NTSTATUS status;
174 DEBUG(10, ("xattr_tdb_getattr called for file %s, name %s\n",
175 file_id_string_tos(id), name));
177 status = xattr_tdb_load_attrs(talloc_tos(), db_ctx, id, &attribs);
179 if (!NT_STATUS_IS_OK(status)) {
180 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
181 nt_errstr(status)));
182 errno = EINVAL;
183 return -1;
186 for (i=0; i<attribs->num_eas; i++) {
187 if (strcmp(attribs->eas[i].name, name) == 0) {
188 break;
192 if (i == attribs->num_eas) {
193 errno = ENOATTR;
194 goto fail;
197 if (attribs->eas[i].value.length > size) {
198 errno = ERANGE;
199 goto fail;
202 memcpy(value, attribs->eas[i].value.data,
203 attribs->eas[i].value.length);
204 result = attribs->eas[i].value.length;
206 fail:
207 TALLOC_FREE(attribs);
208 return result;
211 static ssize_t xattr_tdb_getxattr(struct vfs_handle_struct *handle,
212 const char *path, const char *name,
213 void *value, size_t size)
215 SMB_STRUCT_STAT sbuf;
216 struct file_id id;
217 struct db_context *db;
219 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
221 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
222 return -1;
225 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
227 return xattr_tdb_getattr(db, &id, name, value, size);
230 static ssize_t xattr_tdb_fgetxattr(struct vfs_handle_struct *handle,
231 struct files_struct *fsp,
232 const char *name, void *value, size_t size)
234 SMB_STRUCT_STAT sbuf;
235 struct file_id id;
236 struct db_context *db;
238 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
240 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
241 return -1;
244 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
246 return xattr_tdb_getattr(db, &id, name, value, size);
250 * Worker routine for setxattr and fsetxattr
253 static int xattr_tdb_setattr(struct db_context *db_ctx,
254 const struct file_id *id, const char *name,
255 const void *value, size_t size, int flags)
257 NTSTATUS status;
258 struct db_record *rec;
259 struct tdb_xattrs *attribs;
260 uint32_t i;
262 DEBUG(10, ("xattr_tdb_setattr called for file %s, name %s\n",
263 file_id_string_tos(id), name));
265 rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
267 if (rec == NULL) {
268 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
269 errno = EINVAL;
270 return -1;
273 status = xattr_tdb_pull_attrs(rec, &rec->value, &attribs);
275 if (!NT_STATUS_IS_OK(status)) {
276 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
277 nt_errstr(status)));
278 TALLOC_FREE(rec);
279 return -1;
282 for (i=0; i<attribs->num_eas; i++) {
283 if (strcmp(attribs->eas[i].name, name) == 0) {
284 if (flags & XATTR_CREATE) {
285 TALLOC_FREE(rec);
286 errno = EEXIST;
287 return -1;
289 break;
293 if (i == attribs->num_eas) {
294 struct xattr_EA *tmp;
296 if (flags & XATTR_REPLACE) {
297 TALLOC_FREE(rec);
298 errno = ENOATTR;
299 return -1;
302 tmp = talloc_realloc(
303 attribs, attribs->eas, struct xattr_EA,
304 attribs->num_eas+ 1);
306 if (tmp == NULL) {
307 DEBUG(0, ("talloc_realloc failed\n"));
308 TALLOC_FREE(rec);
309 errno = ENOMEM;
310 return -1;
313 attribs->eas = tmp;
314 attribs->num_eas += 1;
317 attribs->eas[i].name = name;
318 attribs->eas[i].value.data = discard_const_p(uint8, value);
319 attribs->eas[i].value.length = size;
321 status = xattr_tdb_save_attrs(rec, attribs);
323 TALLOC_FREE(rec);
325 if (!NT_STATUS_IS_OK(status)) {
326 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
327 return -1;
330 return 0;
333 static int xattr_tdb_setxattr(struct vfs_handle_struct *handle,
334 const char *path, const char *name,
335 const void *value, size_t size, int flags)
337 SMB_STRUCT_STAT sbuf;
338 struct file_id id;
339 struct db_context *db;
341 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
343 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
344 return -1;
347 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
349 return xattr_tdb_setattr(db, &id, name, value, size, flags);
352 static int xattr_tdb_fsetxattr(struct vfs_handle_struct *handle,
353 struct files_struct *fsp,
354 const char *name, const void *value,
355 size_t size, int flags)
357 SMB_STRUCT_STAT sbuf;
358 struct file_id id;
359 struct db_context *db;
361 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
363 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
364 return -1;
367 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
369 return xattr_tdb_setattr(db, &id, name, value, size, flags);
373 * Worker routine for listxattr and flistxattr
376 static ssize_t xattr_tdb_listattr(struct db_context *db_ctx,
377 const struct file_id *id, char *list,
378 size_t size)
380 NTSTATUS status;
381 struct tdb_xattrs *attribs;
382 uint32_t i;
383 size_t len = 0;
385 status = xattr_tdb_load_attrs(talloc_tos(), db_ctx, id, &attribs);
387 if (!NT_STATUS_IS_OK(status)) {
388 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
389 nt_errstr(status)));
390 errno = EINVAL;
391 return -1;
394 DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n",
395 attribs->num_eas));
397 for (i=0; i<attribs->num_eas; i++) {
398 size_t tmp;
400 DEBUG(10, ("xattr_tdb_listattr: xattrs[i].name: %s\n",
401 attribs->eas[i].name));
403 tmp = strlen(attribs->eas[i].name);
406 * Try to protect against overflow
409 if (len + (tmp+1) < len) {
410 TALLOC_FREE(attribs);
411 errno = EINVAL;
412 return -1;
416 * Take care of the terminating NULL
418 len += (tmp + 1);
421 if (len > size) {
422 TALLOC_FREE(attribs);
423 errno = ERANGE;
424 return -1;
427 len = 0;
429 for (i=0; i<attribs->num_eas; i++) {
430 strlcpy(list+len, attribs->eas[i].name,
431 size-len);
432 len += (strlen(attribs->eas[i].name) + 1);
435 TALLOC_FREE(attribs);
436 return len;
439 static ssize_t xattr_tdb_listxattr(struct vfs_handle_struct *handle,
440 const char *path, char *list, size_t size)
442 SMB_STRUCT_STAT sbuf;
443 struct file_id id;
444 struct db_context *db;
446 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
448 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
449 return -1;
452 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
454 return xattr_tdb_listattr(db, &id, list, size);
457 static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle,
458 struct files_struct *fsp, char *list,
459 size_t size)
461 SMB_STRUCT_STAT sbuf;
462 struct file_id id;
463 struct db_context *db;
465 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
467 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
468 return -1;
471 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
473 return xattr_tdb_listattr(db, &id, list, size);
477 * Worker routine for removexattr and fremovexattr
480 static int xattr_tdb_removeattr(struct db_context *db_ctx,
481 const struct file_id *id, const char *name)
483 NTSTATUS status;
484 struct db_record *rec;
485 struct tdb_xattrs *attribs;
486 uint32_t i;
488 rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
490 if (rec == NULL) {
491 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
492 errno = EINVAL;
493 return -1;
496 status = xattr_tdb_pull_attrs(rec, &rec->value, &attribs);
498 if (!NT_STATUS_IS_OK(status)) {
499 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
500 nt_errstr(status)));
501 TALLOC_FREE(rec);
502 return -1;
505 for (i=0; i<attribs->num_eas; i++) {
506 if (strcmp(attribs->eas[i].name, name) == 0) {
507 break;
511 if (i == attribs->num_eas) {
512 TALLOC_FREE(rec);
513 errno = ENOATTR;
514 return -1;
517 attribs->eas[i] =
518 attribs->eas[attribs->num_eas-1];
519 attribs->num_eas -= 1;
521 if (attribs->num_eas == 0) {
522 rec->delete_rec(rec);
523 TALLOC_FREE(rec);
524 return 0;
527 status = xattr_tdb_save_attrs(rec, attribs);
529 TALLOC_FREE(rec);
531 if (!NT_STATUS_IS_OK(status)) {
532 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
533 return -1;
536 return 0;
539 static int xattr_tdb_removexattr(struct vfs_handle_struct *handle,
540 const char *path, const char *name)
542 SMB_STRUCT_STAT sbuf;
543 struct file_id id;
544 struct db_context *db;
546 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
548 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
549 return -1;
552 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
554 return xattr_tdb_removeattr(db, &id, name);
557 static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle,
558 struct files_struct *fsp, const char *name)
560 SMB_STRUCT_STAT sbuf;
561 struct file_id id;
562 struct db_context *db;
564 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
566 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
567 return -1;
570 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
572 return xattr_tdb_removeattr(db, &id, name);
576 * Open the tdb file upon VFS_CONNECT
579 static bool xattr_tdb_init(int snum, struct db_context **p_db)
581 struct db_context *db;
582 const char *dbname;
583 char *def_dbname;
585 def_dbname = state_path("xattr.tdb");
586 if (def_dbname == NULL) {
587 errno = ENOSYS;
588 return false;
591 dbname = lp_parm_const_string(snum, "xattr_tdb", "file", def_dbname);
593 /* now we know dbname is not NULL */
595 become_root();
596 db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
597 unbecome_root();
599 if (db == NULL) {
600 #if defined(ENOTSUP)
601 errno = ENOTSUP;
602 #else
603 errno = ENOSYS;
604 #endif
605 TALLOC_FREE(def_dbname);
606 return false;
609 *p_db = db;
610 TALLOC_FREE(def_dbname);
611 return true;
615 * On unlink we need to delete the tdb record
617 static int xattr_tdb_unlink(vfs_handle_struct *handle,
618 const struct smb_filename *smb_fname)
620 struct smb_filename *smb_fname_tmp = NULL;
621 struct file_id id;
622 struct db_context *db;
623 struct db_record *rec;
624 NTSTATUS status;
625 int ret = -1;
626 bool remove_record = false;
628 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
630 status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
631 if (!NT_STATUS_IS_OK(status)) {
632 errno = map_errno_from_nt_status(status);
633 return -1;
636 if (lp_posix_pathnames()) {
637 ret = SMB_VFS_LSTAT(handle->conn, smb_fname_tmp);
638 } else {
639 ret = SMB_VFS_STAT(handle->conn, smb_fname_tmp);
641 if (ret == -1) {
642 goto out;
645 if (smb_fname_tmp->st.st_ex_nlink == 1) {
646 /* Only remove record on last link to file. */
647 remove_record = true;
650 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
652 if (ret == -1) {
653 goto out;
656 if (!remove_record) {
657 goto out;
660 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &smb_fname_tmp->st);
662 rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id);
665 * If rec == NULL there's not much we can do about it
668 if (rec != NULL) {
669 rec->delete_rec(rec);
670 TALLOC_FREE(rec);
673 out:
674 TALLOC_FREE(smb_fname_tmp);
675 return ret;
679 * On rmdir we need to delete the tdb record
681 static int xattr_tdb_rmdir(vfs_handle_struct *handle, const char *path)
683 SMB_STRUCT_STAT sbuf;
684 struct file_id id;
685 struct db_context *db;
686 struct db_record *rec;
687 int ret;
689 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
691 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
692 return -1;
695 ret = SMB_VFS_NEXT_RMDIR(handle, path);
697 if (ret == -1) {
698 return -1;
701 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
703 rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id);
706 * If rec == NULL there's not much we can do about it
709 if (rec != NULL) {
710 rec->delete_rec(rec);
711 TALLOC_FREE(rec);
714 return 0;
718 * Destructor for the VFS private data
721 static void close_xattr_db(void **data)
723 struct db_context **p_db = (struct db_context **)data;
724 TALLOC_FREE(*p_db);
727 static int xattr_tdb_connect(vfs_handle_struct *handle, const char *service,
728 const char *user)
730 char *sname = NULL;
731 int res, snum;
732 struct db_context *db;
734 res = SMB_VFS_NEXT_CONNECT(handle, service, user);
735 if (res < 0) {
736 return res;
739 snum = find_service(talloc_tos(), service, &sname);
740 if (snum == -1 || sname == NULL) {
742 * Should not happen, but we should not fail just *here*.
744 return 0;
747 if (!xattr_tdb_init(snum, &db)) {
748 DEBUG(5, ("Could not init xattr tdb\n"));
749 lp_do_parameter(snum, "ea support", "False");
750 return 0;
753 lp_do_parameter(snum, "ea support", "True");
755 SMB_VFS_HANDLE_SET_DATA(handle, db, close_xattr_db,
756 struct db_context, return -1);
758 return 0;
761 static struct vfs_fn_pointers vfs_xattr_tdb_fns = {
762 .getxattr = xattr_tdb_getxattr,
763 .fgetxattr = xattr_tdb_fgetxattr,
764 .setxattr = xattr_tdb_setxattr,
765 .fsetxattr = xattr_tdb_fsetxattr,
766 .listxattr = xattr_tdb_listxattr,
767 .flistxattr = xattr_tdb_flistxattr,
768 .removexattr = xattr_tdb_removexattr,
769 .fremovexattr = xattr_tdb_fremovexattr,
770 .unlink = xattr_tdb_unlink,
771 .rmdir = xattr_tdb_rmdir,
772 .connect_fn = xattr_tdb_connect,
775 NTSTATUS vfs_xattr_tdb_init(void);
776 NTSTATUS vfs_xattr_tdb_init(void)
778 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "xattr_tdb",
779 &vfs_xattr_tdb_fns);