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