vfs_xattr_tdb: move close_xattr_db()
[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,
42                                         path,
43                                         NULL,
44                                         NULL,
45                                         0,
46                                         0);
47         if (smb_fname == NULL) {
48                 TALLOC_FREE(frame);
49                 errno = ENOMEM;
50                 return -1;
51         }
52
53         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
54
55         if (ret == -1) {
56                 TALLOC_FREE(frame); 
57                 return -1;
58         }
59
60         *id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &smb_fname->st);
61         TALLOC_FREE(frame);
62         return 0;
63 }
64
65 struct xattr_tdb_getxattrat_state {
66         struct vfs_aio_state vfs_aio_state;
67         ssize_t xattr_size;
68         uint8_t *xattr_value;
69 };
70
71 static struct tevent_req *xattr_tdb_getxattrat_send(
72                         TALLOC_CTX *mem_ctx,
73                         struct tevent_context *ev,
74                         struct vfs_handle_struct *handle,
75                         files_struct *dir_fsp,
76                         const struct smb_filename *smb_fname,
77                         const char *xattr_name,
78                         size_t alloc_hint)
79 {
80         struct tevent_req *req = NULL;
81         struct xattr_tdb_getxattrat_state *state = NULL;
82         struct smb_filename *cwd = NULL;
83         struct db_context *db = NULL;
84         struct file_id id;
85         int ret;
86         int error;
87         int cwd_ret;
88         DATA_BLOB xattr_blob;
89
90         req = tevent_req_create(mem_ctx, &state,
91                                 struct xattr_tdb_getxattrat_state);
92         if (req == NULL) {
93                 return NULL;
94         }
95         state->xattr_size = -1;
96
97         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
98                                 if (!xattr_tdb_init(-1, state, &db)) {
99                                         tevent_req_error(req, EIO);
100                                         return tevent_req_post(req, ev);
101                                 });
102
103         cwd = SMB_VFS_GETWD(dir_fsp->conn, state);
104         if (tevent_req_nomem(cwd, req)) {
105                 return tevent_req_post(req, ev);
106         }
107
108         ret = SMB_VFS_CHDIR(dir_fsp->conn, dir_fsp->fsp_name);
109         if (ret != 0) {
110                 tevent_req_error(req, errno);
111                 return tevent_req_post(req, ev);
112         }
113
114         ret = xattr_tdb_get_file_id(handle, smb_fname->base_name, &id);
115         error = errno;
116
117         cwd_ret = SMB_VFS_CHDIR(dir_fsp->conn, cwd);
118         SMB_ASSERT(cwd_ret == 0);
119
120         if (ret == -1) {
121                 tevent_req_error(req, error);
122                 return tevent_req_post(req, ev);
123         }
124
125         state->xattr_size = xattr_tdb_getattr(db,
126                                               state,
127                                               &id,
128                                               xattr_name,
129                                               &xattr_blob);
130         if (state->xattr_size == -1) {
131                 tevent_req_error(req, errno);
132                 return tevent_req_post(req, ev);
133         }
134
135         if (alloc_hint == 0) {
136                 /*
137                  * The caller only wants to know the size.
138                  */
139                 tevent_req_done(req);
140                 return tevent_req_post(req, ev);
141         }
142
143         if (state->xattr_size == 0) {
144                 /*
145                  * There's no data.
146                  */
147                 tevent_req_done(req);
148                 return tevent_req_post(req, ev);
149         }
150
151         if (xattr_blob.length > alloc_hint) {
152                 /*
153                  * The data doesn't fit.
154                  */
155                 state->xattr_size = -1;
156                 tevent_req_error(req, ERANGE);
157                 return tevent_req_post(req, ev);
158         }
159
160         /*
161          * take the whole blob.
162          */
163         state->xattr_value = xattr_blob.data;
164
165         tevent_req_done(req);
166         return tevent_req_post(req, ev);
167 }
168
169 static ssize_t xattr_tdb_getxattrat_recv(struct tevent_req *req,
170                                          struct vfs_aio_state *aio_state,
171                                          TALLOC_CTX *mem_ctx,
172                                          uint8_t **xattr_value)
173 {
174         struct xattr_tdb_getxattrat_state *state = tevent_req_data(
175                 req, struct xattr_tdb_getxattrat_state);
176         ssize_t xattr_size;
177
178         if (tevent_req_is_unix_error(req, &aio_state->error)) {
179                 tevent_req_received(req);
180                 return -1;
181         }
182
183         *aio_state = state->vfs_aio_state;
184         xattr_size = state->xattr_size;
185         if (xattr_value != NULL) {
186                 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
187         }
188
189         tevent_req_received(req);
190         return xattr_size;
191 }
192
193 static ssize_t xattr_tdb_fgetxattr(struct vfs_handle_struct *handle,
194                                    struct files_struct *fsp,
195                                    const char *name, void *value, size_t size)
196 {
197         SMB_STRUCT_STAT sbuf;
198         struct file_id id;
199         struct db_context *db;
200         ssize_t xattr_size;
201         DATA_BLOB blob;
202         TALLOC_CTX *frame = talloc_stackframe();
203
204         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
205                                 if (!xattr_tdb_init(-1, frame, &db))
206                                 {
207                                         TALLOC_FREE(frame); return -1;
208                                 });
209
210         if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
211                 TALLOC_FREE(frame);
212                 return -1;
213         }
214
215         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
216
217         xattr_size = xattr_tdb_getattr(db, frame, &id, name, &blob);
218         if (xattr_size < 0) {
219                 errno = ENOATTR;
220                 TALLOC_FREE(frame);
221                 return -1;
222         }
223
224         if (size == 0) {
225                 TALLOC_FREE(frame);
226                 return xattr_size;
227         }
228
229         if (blob.length > size) {
230                 TALLOC_FREE(frame);
231                 errno = ERANGE;
232                 return -1;
233         }
234         memcpy(value, blob.data, xattr_size);
235         TALLOC_FREE(frame);
236         return xattr_size;
237 }
238
239 static int xattr_tdb_fsetxattr(struct vfs_handle_struct *handle,
240                                struct files_struct *fsp,
241                                const char *name, const void *value,
242                                size_t size, int flags)
243 {
244         SMB_STRUCT_STAT sbuf;
245         struct file_id id;
246         struct db_context *db;
247         int ret;
248         TALLOC_CTX *frame = talloc_stackframe();
249
250         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
251                                 if (!xattr_tdb_init(-1, frame, &db))
252                                 {
253                                         TALLOC_FREE(frame); return -1;
254                                 });
255
256         if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
257                 TALLOC_FREE(frame);
258                 return -1;
259         }
260
261         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
262
263         ret = xattr_tdb_setattr(db, &id, name, value, size, flags);
264         TALLOC_FREE(frame);
265         return ret;
266
267 }
268
269 static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle,
270                                     struct files_struct *fsp, char *list,
271                                     size_t size)
272 {
273         SMB_STRUCT_STAT sbuf;
274         struct file_id id;
275         struct db_context *db;
276         int ret;
277         TALLOC_CTX *frame = talloc_stackframe();
278
279         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
280                                 if (!xattr_tdb_init(-1, frame, &db))
281                                 {
282                                         TALLOC_FREE(frame); return -1;
283                                 });
284
285         if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
286                 TALLOC_FREE(frame);
287                 return -1;
288         }
289
290         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
291
292         ret = xattr_tdb_listattr(db, &id, list, size);
293         TALLOC_FREE(frame);
294         return ret;
295 }
296
297 static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle,
298                                   struct files_struct *fsp, const char *name)
299 {
300         SMB_STRUCT_STAT sbuf;
301         struct file_id id;
302         struct db_context *db;
303         int ret;
304         TALLOC_CTX *frame = talloc_stackframe();
305
306         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
307                                 if (!xattr_tdb_init(-1, frame, &db))
308                                 {
309                                         TALLOC_FREE(frame); return -1;
310                                 });
311
312         if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
313                 TALLOC_FREE(frame);
314                 return -1;
315         }
316
317         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
318
319         ret = xattr_tdb_removeattr(db, &id, name);
320         TALLOC_FREE(frame);
321         return ret;
322 }
323
324 /*
325  * Destructor for the VFS private data
326  */
327
328 static void close_xattr_db(void **data)
329 {
330         struct db_context **p_db = (struct db_context **)data;
331         TALLOC_FREE(*p_db);
332 }
333
334 /*
335  * Open the tdb file upon VFS_CONNECT
336  */
337
338 static bool xattr_tdb_init(int snum, TALLOC_CTX *mem_ctx, struct db_context **p_db)
339 {
340         struct db_context *db;
341         const char *dbname;
342         char *def_dbname;
343
344         def_dbname = state_path(talloc_tos(), "xattr.tdb");
345         if (def_dbname == NULL) {
346                 errno = ENOSYS;
347                 return false;
348         }
349
350         dbname = lp_parm_const_string(snum, "xattr_tdb", "file", def_dbname);
351
352         /* now we know dbname is not NULL */
353
354         become_root();
355         db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
356                      DBWRAP_LOCK_ORDER_2, DBWRAP_FLAG_NONE);
357         unbecome_root();
358
359         if (db == NULL) {
360 #if defined(ENOTSUP)
361                 errno = ENOTSUP;
362 #else
363                 errno = ENOSYS;
364 #endif
365                 TALLOC_FREE(def_dbname);
366                 return false;
367         }
368
369         *p_db = db;
370         TALLOC_FREE(def_dbname);
371         return true;
372 }
373
374 static int xattr_tdb_openat(struct vfs_handle_struct *handle,
375                             const struct files_struct *dirfsp,
376                             const struct smb_filename *smb_fname,
377                             struct files_struct *fsp,
378                             const struct vfs_open_how *how)
379 {
380         struct db_context *db = NULL;
381         TALLOC_CTX *frame = NULL;
382         SMB_STRUCT_STAT sbuf;
383         int fd;
384         int ret;
385
386         fd = SMB_VFS_NEXT_OPENAT(handle,
387                                  dirfsp,
388                                  smb_fname,
389                                  fsp,
390                                  how);
391         if (fd == -1) {
392                 return -1;
393         }
394
395         if ((how->flags & (O_CREAT|O_EXCL)) != (O_CREAT|O_EXCL)) {
396                 return fd;
397         }
398
399         /*
400          * We know we used O_CREAT|O_EXCL and it worked.
401          * We must have created the file.
402          */
403
404         fsp_set_fd(fsp, fd);
405         ret = SMB_VFS_FSTAT(fsp, &sbuf);
406         fsp_set_fd(fsp, -1);
407         if (ret == -1) {
408                 /* Can't happen... */
409                 DBG_WARNING("SMB_VFS_FSTAT failed on file %s (%s)\n",
410                             smb_fname_str_dbg(smb_fname),
411                             strerror(errno));
412                 return -1;
413         }
414
415         fsp->file_id = SMB_VFS_FILE_ID_CREATE(fsp->conn, &sbuf);
416
417         frame = talloc_stackframe();
418
419         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
420                                 if (!xattr_tdb_init(-1, frame, &db))
421                                 {
422                                         TALLOC_FREE(frame); return -1;
423                                 });
424
425         xattr_tdb_remove_all_attrs(db, &fsp->file_id);
426
427         TALLOC_FREE(frame);
428         return fd;
429 }
430
431 static int xattr_tdb_mkdirat(vfs_handle_struct *handle,
432                 struct files_struct *dirfsp,
433                 const struct smb_filename *smb_fname,
434                 mode_t mode)
435 {
436         struct db_context *db = NULL;
437         TALLOC_CTX *frame = NULL;
438         struct file_id fileid;
439         int ret;
440         struct smb_filename *full_fname = NULL;
441
442         ret = SMB_VFS_NEXT_MKDIRAT(handle,
443                                 dirfsp,
444                                 smb_fname,
445                                 mode);
446         if (ret < 0) {
447                 return ret;
448         }
449
450         frame = talloc_stackframe();
451
452         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
453                                                   dirfsp,
454                                                   smb_fname);
455         if (full_fname == NULL) {
456                 errno = ENOMEM;
457                 return -1;
458         }
459
460         /* Always use LSTAT here - we just created the directory. */
461         ret = SMB_VFS_LSTAT(handle->conn, full_fname);
462         if (ret == -1) {
463                 /* Rename race. Let upper level take care of it. */
464                 TALLOC_FREE(frame);
465                 return -1;
466         }
467         if (!S_ISDIR(full_fname->st.st_ex_mode)) {
468                 /* Rename race. Let upper level take care of it. */
469                 TALLOC_FREE(frame);
470                 return -1;
471         }
472
473         fileid = SMB_VFS_FILE_ID_CREATE(handle->conn, &full_fname->st);
474
475         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
476                                 if (!xattr_tdb_init(-1, frame, &db))
477                                 {
478                                         TALLOC_FREE(frame); return -1;
479                                 });
480
481         xattr_tdb_remove_all_attrs(db, &fileid);
482         TALLOC_FREE(frame);
483         return 0;
484 }
485
486 /*
487  * On unlink we need to delete the tdb record
488  */
489 static int xattr_tdb_unlinkat(vfs_handle_struct *handle,
490                         struct files_struct *dirfsp,
491                         const struct smb_filename *smb_fname,
492                         int flags)
493 {
494         struct smb_filename *smb_fname_tmp = NULL;
495         struct smb_filename *full_fname = NULL;
496         struct file_id id;
497         struct db_context *db;
498         int ret = -1;
499         bool remove_record = false;
500         TALLOC_CTX *frame = talloc_stackframe();
501
502         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
503                                 if (!xattr_tdb_init(-1, frame, &db))
504                                 {
505                                         TALLOC_FREE(frame); return -1;
506                                 });
507
508         smb_fname_tmp = cp_smb_filename(frame, smb_fname);
509         if (smb_fname_tmp == NULL) {
510                 TALLOC_FREE(frame);
511                 errno = ENOMEM;
512                 return -1;
513         }
514
515         /*
516          * TODO: use SMB_VFS_STATX() once we have that
517          */
518
519         full_fname = full_path_from_dirfsp_atname(frame,
520                                                   dirfsp,
521                                                   smb_fname);
522         if (full_fname == NULL) {
523                 goto out;
524         }
525
526         if (full_fname->flags & SMB_FILENAME_POSIX_PATH) {
527                 ret = SMB_VFS_NEXT_LSTAT(handle, full_fname);
528         } else {
529                 ret = SMB_VFS_NEXT_STAT(handle, full_fname);
530                 if (ret == -1 && (errno == ENOENT || errno == ELOOP)) {
531                         if (VALID_STAT(smb_fname->st) &&
532                                         S_ISLNK(smb_fname->st.st_ex_mode)) {
533                                 /*
534                                  * Original name was a link - Could be
535                                  * trying to remove a dangling symlink.
536                                  */
537                                 ret = SMB_VFS_NEXT_LSTAT(handle, full_fname);
538                         }
539                 }
540         }
541         if (ret == -1) {
542                 goto out;
543         }
544         smb_fname_tmp->st = full_fname->st;
545
546         if (flags & AT_REMOVEDIR) {
547                 /* Always remove record when removing a directory succeeds. */
548                 remove_record = true;
549         } else {
550                 if (smb_fname_tmp->st.st_ex_nlink == 1) {
551                         /* Only remove record on last link to file. */
552                         remove_record = true;
553                 }
554         }
555
556         ret = SMB_VFS_NEXT_UNLINKAT(handle,
557                                 dirfsp,
558                                 smb_fname_tmp,
559                                 flags);
560
561         if (ret == -1) {
562                 goto out;
563         }
564
565         if (!remove_record) {
566                 goto out;
567         }
568
569         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &smb_fname_tmp->st);
570
571         xattr_tdb_remove_all_attrs(db, &id);
572
573  out:
574         TALLOC_FREE(frame);
575         return ret;
576 }
577
578 static int xattr_tdb_connect(vfs_handle_struct *handle, const char *service,
579                           const char *user)
580 {
581         char *sname = NULL;
582         int res, snum;
583         struct db_context *db;
584
585         res = SMB_VFS_NEXT_CONNECT(handle, service, user);
586         if (res < 0) {
587                 return res;
588         }
589
590         snum = find_service(talloc_tos(), service, &sname);
591         if (snum == -1 || sname == NULL) {
592                 /*
593                  * Should not happen, but we should not fail just *here*.
594                  */
595                 return 0;
596         }
597
598         if (!xattr_tdb_init(snum, NULL, &db)) {
599                 DEBUG(5, ("Could not init xattr tdb\n"));
600                 lp_do_parameter(snum, "ea support", "False");
601                 return 0;
602         }
603
604         lp_do_parameter(snum, "ea support", "True");
605
606         SMB_VFS_HANDLE_SET_DATA(handle, db, close_xattr_db,
607                                 struct db_context, return -1);
608
609         return 0;
610 }
611
612 static struct vfs_fn_pointers vfs_xattr_tdb_fns = {
613         .getxattrat_send_fn = xattr_tdb_getxattrat_send,
614         .getxattrat_recv_fn = xattr_tdb_getxattrat_recv,
615         .fgetxattr_fn = xattr_tdb_fgetxattr,
616         .fsetxattr_fn = xattr_tdb_fsetxattr,
617         .flistxattr_fn = xattr_tdb_flistxattr,
618         .fremovexattr_fn = xattr_tdb_fremovexattr,
619         .openat_fn = xattr_tdb_openat,
620         .mkdirat_fn = xattr_tdb_mkdirat,
621         .unlinkat_fn = xattr_tdb_unlinkat,
622         .connect_fn = xattr_tdb_connect,
623 };
624
625 static_decl_vfs;
626 NTSTATUS vfs_xattr_tdb_init(TALLOC_CTX *ctx)
627 {
628         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "xattr_tdb",
629                                 &vfs_xattr_tdb_fns);
630 }