s3: VFS: vfs_xattr_tdb: Remove rmdir_fn. No longer used.
[samba.git] / source3 / modules / vfs_xattr_tdb.c
1 /*
2  * Store posix-level xattrs in a tdb
3  *
4  * Copyright (C) Volker Lendecke, 2007
5  * Copyright (C) Andrew Bartlett, 2012
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "smbd/smbd.h"
24 #include "dbwrap/dbwrap.h"
25 #include "dbwrap/dbwrap_open.h"
26 #include "source3/lib/xattr_tdb.h"
27 #include "lib/util/tevent_unix.h"
28
29 #undef DBGC_CLASS
30 #define DBGC_CLASS DBGC_VFS
31
32 static bool xattr_tdb_init(int snum, TALLOC_CTX *mem_ctx, struct db_context **p_db);
33
34 static int xattr_tdb_get_file_id(struct vfs_handle_struct *handle,
35                                 const char *path, struct file_id *id)
36 {
37         int ret;
38         TALLOC_CTX *frame = talloc_stackframe();
39         struct smb_filename *smb_fname;
40
41         smb_fname = synthetic_smb_fname(frame, path, NULL, NULL, 0);
42         if (smb_fname == NULL) {
43                 TALLOC_FREE(frame);
44                 errno = ENOMEM;
45                 return -1;
46         }
47
48         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
49
50         if (ret == -1) {
51                 TALLOC_FREE(frame); 
52                 return -1;
53         }
54
55         *id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &smb_fname->st);
56         TALLOC_FREE(frame);
57         return 0;
58 }
59
60 static ssize_t xattr_tdb_getxattr(struct vfs_handle_struct *handle,
61                                 const struct smb_filename *smb_fname,
62                                 const char *name,
63                                 void *value,
64                                 size_t size)
65 {
66         struct file_id id;
67         struct db_context *db;
68         ssize_t xattr_size;
69         int ret;
70         DATA_BLOB blob;
71         TALLOC_CTX *frame = talloc_stackframe();
72
73         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
74                                 if (!xattr_tdb_init(-1, frame, &db))
75                                 {
76                                         TALLOC_FREE(frame); return -1;
77                                 });
78
79         ret = xattr_tdb_get_file_id(handle, smb_fname->base_name, &id);
80         if (ret == -1) {
81                 TALLOC_FREE(frame);
82                 return -1;
83         }
84
85         xattr_size = xattr_tdb_getattr(db, frame, &id, name, &blob);
86         if (xattr_size < 0) {
87                 errno = ENOATTR;
88                 TALLOC_FREE(frame);
89                 return -1;
90         }
91
92         if (size == 0) {
93                 TALLOC_FREE(frame);
94                 return xattr_size;
95         }
96
97         if (blob.length > size) {
98                 TALLOC_FREE(frame);
99                 errno = ERANGE;
100                 return -1;
101         }
102         memcpy(value, blob.data, xattr_size);
103         TALLOC_FREE(frame);
104         return xattr_size;
105 }
106
107 struct xattr_tdb_getxattrat_state {
108         struct vfs_aio_state vfs_aio_state;
109         ssize_t xattr_size;
110         uint8_t *xattr_value;
111 };
112
113 static struct tevent_req *xattr_tdb_getxattrat_send(
114                         TALLOC_CTX *mem_ctx,
115                         struct tevent_context *ev,
116                         struct vfs_handle_struct *handle,
117                         files_struct *dir_fsp,
118                         const struct smb_filename *smb_fname,
119                         const char *xattr_name,
120                         size_t alloc_hint)
121 {
122         struct tevent_req *req = NULL;
123         struct xattr_tdb_getxattrat_state *state = NULL;
124         struct smb_filename *cwd = NULL;
125         struct db_context *db = NULL;
126         struct file_id id;
127         int ret;
128         int error;
129         int cwd_ret;
130         DATA_BLOB xattr_blob;
131
132         req = tevent_req_create(mem_ctx, &state,
133                                 struct xattr_tdb_getxattrat_state);
134         if (req == NULL) {
135                 return NULL;
136         }
137         state->xattr_size = -1;
138
139         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
140                                 if (!xattr_tdb_init(-1, state, &db)) {
141                                         tevent_req_error(req, EIO);
142                                         return tevent_req_post(req, ev);
143                                 });
144
145         cwd = SMB_VFS_GETWD(dir_fsp->conn, state);
146         if (tevent_req_nomem(cwd, req)) {
147                 return tevent_req_post(req, ev);
148         }
149
150         ret = SMB_VFS_CHDIR(dir_fsp->conn, dir_fsp->fsp_name);
151         if (ret != 0) {
152                 tevent_req_error(req, errno);
153                 return tevent_req_post(req, ev);
154         }
155
156         ret = xattr_tdb_get_file_id(handle, smb_fname->base_name, &id);
157         error = errno;
158
159         cwd_ret = SMB_VFS_CHDIR(dir_fsp->conn, cwd);
160         SMB_ASSERT(cwd_ret == 0);
161
162         if (ret == -1) {
163                 tevent_req_error(req, error);
164                 return tevent_req_post(req, ev);
165         }
166
167         state->xattr_size = xattr_tdb_getattr(db,
168                                               state,
169                                               &id,
170                                               xattr_name,
171                                               &xattr_blob);
172         if (state->xattr_size == -1) {
173                 tevent_req_error(req, errno);
174                 return tevent_req_post(req, ev);
175         }
176
177         if (alloc_hint == 0) {
178                 /*
179                  * The caller only wants to know the size.
180                  */
181                 tevent_req_done(req);
182                 return tevent_req_post(req, ev);
183         }
184
185         if (state->xattr_size == 0) {
186                 /*
187                  * There's no data.
188                  */
189                 tevent_req_done(req);
190                 return tevent_req_post(req, ev);
191         }
192
193         if (xattr_blob.length > alloc_hint) {
194                 /*
195                  * The data doesn't fit.
196                  */
197                 state->xattr_size = -1;
198                 tevent_req_error(req, ERANGE);
199                 return tevent_req_post(req, ev);
200         }
201
202         /*
203          * take the whole blob.
204          */
205         state->xattr_value = xattr_blob.data;
206
207         tevent_req_done(req);
208         return tevent_req_post(req, ev);
209 }
210
211 static ssize_t xattr_tdb_getxattrat_recv(struct tevent_req *req,
212                                          struct vfs_aio_state *aio_state,
213                                          TALLOC_CTX *mem_ctx,
214                                          uint8_t **xattr_value)
215 {
216         struct xattr_tdb_getxattrat_state *state = tevent_req_data(
217                 req, struct xattr_tdb_getxattrat_state);
218         ssize_t xattr_size;
219
220         if (tevent_req_is_unix_error(req, &aio_state->error)) {
221                 tevent_req_received(req);
222                 return -1;
223         }
224
225         *aio_state = state->vfs_aio_state;
226         xattr_size = state->xattr_size;
227         if (xattr_value != NULL) {
228                 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
229         }
230
231         tevent_req_received(req);
232         return xattr_size;
233 }
234
235 static ssize_t xattr_tdb_fgetxattr(struct vfs_handle_struct *handle,
236                                    struct files_struct *fsp,
237                                    const char *name, void *value, size_t size)
238 {
239         SMB_STRUCT_STAT sbuf;
240         struct file_id id;
241         struct db_context *db;
242         ssize_t xattr_size;
243         DATA_BLOB blob;
244         TALLOC_CTX *frame = talloc_stackframe();
245
246         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
247                                 if (!xattr_tdb_init(-1, frame, &db))
248                                 {
249                                         TALLOC_FREE(frame); return -1;
250                                 });
251
252         if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
253                 TALLOC_FREE(frame);
254                 return -1;
255         }
256
257         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
258
259         xattr_size = xattr_tdb_getattr(db, frame, &id, name, &blob);
260         if (xattr_size < 0) {
261                 errno = ENOATTR;
262                 TALLOC_FREE(frame);
263                 return -1;
264         }
265
266         if (size == 0) {
267                 TALLOC_FREE(frame);
268                 return xattr_size;
269         }
270
271         if (blob.length > size) {
272                 TALLOC_FREE(frame);
273                 errno = ERANGE;
274                 return -1;
275         }
276         memcpy(value, blob.data, xattr_size);
277         TALLOC_FREE(frame);
278         return xattr_size;
279 }
280
281 static int xattr_tdb_setxattr(struct vfs_handle_struct *handle,
282                                 const struct smb_filename *smb_fname,
283                                 const char *name,
284                                 const void *value,
285                                 size_t size,
286                                 int flags)
287 {
288         struct file_id id;
289         struct db_context *db;
290         int ret;
291         TALLOC_CTX *frame = talloc_stackframe();
292
293         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
294                                 if (!xattr_tdb_init(-1, frame, &db))
295                                 {
296                                         TALLOC_FREE(frame); return -1;
297                                 });
298
299         ret = xattr_tdb_get_file_id(handle, smb_fname->base_name, &id);
300         if (ret == -1) {
301                 TALLOC_FREE(frame);
302                 return -1;
303         }
304
305         ret = xattr_tdb_setattr(db, &id, name, value, size, flags);
306         TALLOC_FREE(frame);
307         return ret;
308 }
309
310 static int xattr_tdb_fsetxattr(struct vfs_handle_struct *handle,
311                                struct files_struct *fsp,
312                                const char *name, const void *value,
313                                size_t size, int flags)
314 {
315         SMB_STRUCT_STAT sbuf;
316         struct file_id id;
317         struct db_context *db;
318         int ret;
319         TALLOC_CTX *frame = talloc_stackframe();
320
321         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
322                                 if (!xattr_tdb_init(-1, frame, &db))
323                                 {
324                                         TALLOC_FREE(frame); return -1;
325                                 });
326
327         if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
328                 TALLOC_FREE(frame);
329                 return -1;
330         }
331
332         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
333
334         ret = xattr_tdb_setattr(db, &id, name, value, size, flags);
335         TALLOC_FREE(frame);
336         return ret;
337
338 }
339
340 static ssize_t xattr_tdb_listxattr(struct vfs_handle_struct *handle,
341                                 const struct smb_filename *smb_fname,
342                                 char *list,
343                                 size_t size)
344 {
345         struct file_id id;
346         struct db_context *db;
347         int ret;
348         TALLOC_CTX *frame = talloc_stackframe();
349
350         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
351                                 if (!xattr_tdb_init(-1, frame, &db))
352                                 {
353                                         TALLOC_FREE(frame); return -1;
354                                 });
355
356         ret = xattr_tdb_get_file_id(handle, smb_fname->base_name, &id);
357         if (ret == -1) {
358                 TALLOC_FREE(frame);
359                 return -1;
360         }
361
362         ret = xattr_tdb_listattr(db, &id, list, size);
363         TALLOC_FREE(frame);
364         return ret;
365
366 }
367
368 static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle,
369                                     struct files_struct *fsp, char *list,
370                                     size_t size)
371 {
372         SMB_STRUCT_STAT sbuf;
373         struct file_id id;
374         struct db_context *db;
375         int ret;
376         TALLOC_CTX *frame = talloc_stackframe();
377
378         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
379                                 if (!xattr_tdb_init(-1, frame, &db))
380                                 {
381                                         TALLOC_FREE(frame); return -1;
382                                 });
383
384         if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
385                 TALLOC_FREE(frame);
386                 return -1;
387         }
388
389         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
390
391         ret = xattr_tdb_listattr(db, &id, list, size);
392         TALLOC_FREE(frame);
393         return ret;
394 }
395
396 static int xattr_tdb_removexattr(struct vfs_handle_struct *handle,
397                                 const struct smb_filename *smb_fname,
398                                 const char *name)
399 {
400         struct file_id id;
401         struct db_context *db;
402         int ret;
403         TALLOC_CTX *frame = talloc_stackframe();
404
405         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
406                                 if (!xattr_tdb_init(-1, frame, &db))
407                                 {
408                                         TALLOC_FREE(frame); return -1;
409                                 });
410
411         ret = xattr_tdb_get_file_id(handle, smb_fname->base_name, &id);
412         if (ret == -1) {
413                 TALLOC_FREE(frame);
414                 return ret;
415         }
416
417         
418         ret = xattr_tdb_removeattr(db, &id, name);
419         TALLOC_FREE(frame);
420         return ret;
421 }
422
423 static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle,
424                                   struct files_struct *fsp, const char *name)
425 {
426         SMB_STRUCT_STAT sbuf;
427         struct file_id id;
428         struct db_context *db;
429         int ret;
430         TALLOC_CTX *frame = talloc_stackframe();
431
432         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
433                                 if (!xattr_tdb_init(-1, frame, &db))
434                                 {
435                                         TALLOC_FREE(frame); return -1;
436                                 });
437
438         if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
439                 TALLOC_FREE(frame);
440                 return -1;
441         }
442
443         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
444
445         ret = xattr_tdb_removeattr(db, &id, name);
446         TALLOC_FREE(frame);
447         return ret;
448 }
449
450 /*
451  * Open the tdb file upon VFS_CONNECT
452  */
453
454 static bool xattr_tdb_init(int snum, TALLOC_CTX *mem_ctx, struct db_context **p_db)
455 {
456         struct db_context *db;
457         const char *dbname;
458         char *def_dbname;
459
460         def_dbname = state_path(talloc_tos(), "xattr.tdb");
461         if (def_dbname == NULL) {
462                 errno = ENOSYS;
463                 return false;
464         }
465
466         dbname = lp_parm_const_string(snum, "xattr_tdb", "file", def_dbname);
467
468         /* now we know dbname is not NULL */
469
470         become_root();
471         db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
472                      DBWRAP_LOCK_ORDER_2, DBWRAP_FLAG_NONE);
473         unbecome_root();
474
475         if (db == NULL) {
476 #if defined(ENOTSUP)
477                 errno = ENOTSUP;
478 #else
479                 errno = ENOSYS;
480 #endif
481                 TALLOC_FREE(def_dbname);
482                 return false;
483         }
484
485         *p_db = db;
486         TALLOC_FREE(def_dbname);
487         return true;
488 }
489
490 static int xattr_tdb_open(vfs_handle_struct *handle,
491                         struct smb_filename *smb_fname,
492                         files_struct *fsp,
493                         int flags,
494                         mode_t mode)
495 {
496         struct db_context *db = NULL;
497         TALLOC_CTX *frame = NULL;
498         int ret;
499
500         fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle,
501                                 smb_fname, fsp,
502                                 flags,
503                                 mode);
504
505         if (fsp->fh->fd < 0) {
506                 return fsp->fh->fd;
507         }
508
509         if ((flags & (O_CREAT|O_EXCL)) != (O_CREAT|O_EXCL)) {
510                 return fsp->fh->fd;
511         }
512
513         /*
514          * We know we used O_CREAT|O_EXCL and it worked.
515          * We must have created the file.
516          */
517
518         ret = SMB_VFS_FSTAT(fsp, &smb_fname->st);
519         if (ret == -1) {
520                 /* Can't happen... */
521                 DBG_WARNING("SMB_VFS_FSTAT failed on file %s (%s)\n",
522                         smb_fname_str_dbg(smb_fname),
523                         strerror(errno));
524                 return -1;
525         }
526         fsp->file_id = SMB_VFS_FILE_ID_CREATE(fsp->conn, &smb_fname->st);
527
528         frame = talloc_stackframe();
529         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
530                                 if (!xattr_tdb_init(-1, frame, &db))
531                                 {
532                                         TALLOC_FREE(frame); return -1;
533                                 });
534
535         xattr_tdb_remove_all_attrs(db, &fsp->file_id);
536         TALLOC_FREE(frame);
537         return fsp->fh->fd;
538 }
539
540 static int xattr_tdb_mkdirat(vfs_handle_struct *handle,
541                 struct files_struct *dirfsp,
542                 const struct smb_filename *smb_fname,
543                 mode_t mode)
544 {
545         struct db_context *db = NULL;
546         TALLOC_CTX *frame = NULL;
547         struct file_id fileid;
548         int ret;
549         struct smb_filename *smb_fname_tmp = NULL;
550
551         ret = SMB_VFS_NEXT_MKDIRAT(handle,
552                                 dirfsp,
553                                 smb_fname,
554                                 mode);
555         if (ret < 0) {
556                 return ret;
557         }
558
559         frame = talloc_stackframe();
560         smb_fname_tmp = cp_smb_filename(frame, smb_fname);
561         if (smb_fname_tmp == NULL) {
562                 TALLOC_FREE(frame);
563                 errno = ENOMEM;
564                 return -1;
565         }
566
567         /* Always use LSTAT here - we just creaded the directory. */
568         ret = SMB_VFS_LSTAT(handle->conn, smb_fname_tmp);
569         if (ret == -1) {
570                 /* Rename race. Let upper level take care of it. */
571                 TALLOC_FREE(frame);
572                 return -1;
573         }
574         if (!S_ISDIR(smb_fname_tmp->st.st_ex_mode)) {
575                 /* Rename race. Let upper level take care of it. */
576                 TALLOC_FREE(frame);
577                 return -1;
578         }
579
580         fileid = SMB_VFS_FILE_ID_CREATE(handle->conn, &smb_fname_tmp->st);
581
582         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
583                                 if (!xattr_tdb_init(-1, frame, &db))
584                                 {
585                                         TALLOC_FREE(frame); return -1;
586                                 });
587
588         xattr_tdb_remove_all_attrs(db, &fileid);
589         TALLOC_FREE(frame);
590         return 0;
591 }
592
593 /*
594  * On unlink we need to delete the tdb record
595  */
596 static int xattr_tdb_unlinkat(vfs_handle_struct *handle,
597                         struct files_struct *dirfsp,
598                         const struct smb_filename *smb_fname,
599                         int flags)
600 {
601         struct smb_filename *smb_fname_tmp = NULL;
602         struct file_id id;
603         struct db_context *db;
604         int ret = -1;
605         bool remove_record = false;
606         TALLOC_CTX *frame = talloc_stackframe();
607
608         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
609                                 if (!xattr_tdb_init(-1, frame, &db))
610                                 {
611                                         TALLOC_FREE(frame); return -1;
612                                 });
613
614         smb_fname_tmp = cp_smb_filename(frame, smb_fname);
615         if (smb_fname_tmp == NULL) {
616                 TALLOC_FREE(frame);
617                 errno = ENOMEM;
618                 return -1;
619         }
620
621         if (smb_fname_tmp->flags & SMB_FILENAME_POSIX_PATH) {
622                 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_tmp);
623         } else {
624                 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_tmp);
625         }
626         if (ret == -1) {
627                 goto out;
628         }
629
630         if (flags & AT_REMOVEDIR) {
631                 /* Always remove record when removing a directory succeeds. */
632                 remove_record = true;
633         } else {
634                 if (smb_fname_tmp->st.st_ex_nlink == 1) {
635                         /* Only remove record on last link to file. */
636                         remove_record = true;
637                 }
638         }
639
640         ret = SMB_VFS_NEXT_UNLINKAT(handle,
641                                 dirfsp,
642                                 smb_fname_tmp,
643                                 flags);
644
645         if (ret == -1) {
646                 goto out;
647         }
648
649         if (!remove_record) {
650                 goto out;
651         }
652
653         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &smb_fname_tmp->st);
654
655         xattr_tdb_remove_all_attrs(db, &id);
656
657  out:
658         TALLOC_FREE(frame);
659         return ret;
660 }
661
662 /*
663  * Destructor for the VFS private data
664  */
665
666 static void close_xattr_db(void **data)
667 {
668         struct db_context **p_db = (struct db_context **)data;
669         TALLOC_FREE(*p_db);
670 }
671
672 static int xattr_tdb_connect(vfs_handle_struct *handle, const char *service,
673                           const char *user)
674 {
675         char *sname = NULL;
676         int res, snum;
677         struct db_context *db;
678
679         res = SMB_VFS_NEXT_CONNECT(handle, service, user);
680         if (res < 0) {
681                 return res;
682         }
683
684         snum = find_service(talloc_tos(), service, &sname);
685         if (snum == -1 || sname == NULL) {
686                 /*
687                  * Should not happen, but we should not fail just *here*.
688                  */
689                 return 0;
690         }
691
692         if (!xattr_tdb_init(snum, NULL, &db)) {
693                 DEBUG(5, ("Could not init xattr tdb\n"));
694                 lp_do_parameter(snum, "ea support", "False");
695                 return 0;
696         }
697
698         lp_do_parameter(snum, "ea support", "True");
699
700         SMB_VFS_HANDLE_SET_DATA(handle, db, close_xattr_db,
701                                 struct db_context, return -1);
702
703         return 0;
704 }
705
706 static struct vfs_fn_pointers vfs_xattr_tdb_fns = {
707         .getxattr_fn = xattr_tdb_getxattr,
708         .getxattrat_send_fn = xattr_tdb_getxattrat_send,
709         .getxattrat_recv_fn = xattr_tdb_getxattrat_recv,
710         .fgetxattr_fn = xattr_tdb_fgetxattr,
711         .setxattr_fn = xattr_tdb_setxattr,
712         .fsetxattr_fn = xattr_tdb_fsetxattr,
713         .listxattr_fn = xattr_tdb_listxattr,
714         .flistxattr_fn = xattr_tdb_flistxattr,
715         .removexattr_fn = xattr_tdb_removexattr,
716         .fremovexattr_fn = xattr_tdb_fremovexattr,
717         .open_fn = xattr_tdb_open,
718         .mkdirat_fn = xattr_tdb_mkdirat,
719         .unlinkat_fn = xattr_tdb_unlinkat,
720         .connect_fn = xattr_tdb_connect,
721 };
722
723 static_decl_vfs;
724 NTSTATUS vfs_xattr_tdb_init(TALLOC_CTX *ctx)
725 {
726         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "xattr_tdb",
727                                 &vfs_xattr_tdb_fns);
728 }