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