lib: modules: Change XXX_init interface from XXX_init(void) to XXX_init(TALLOC_CTX *)
[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 char *path, char *list, size_t size)
208 {
209         struct file_id id;
210         struct db_context *db;
211         int ret;
212         TALLOC_CTX *frame = talloc_stackframe();
213
214         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
215                                 if (!xattr_tdb_init(-1, frame, &db))
216                                 {
217                                         TALLOC_FREE(frame); return -1;
218                                 });
219
220         ret = xattr_tdb_get_file_id(handle, path, &id);
221         if (ret == -1) {
222                 TALLOC_FREE(frame);
223                 return -1;
224         }
225
226         ret = xattr_tdb_listattr(db, &id, list, size);
227         TALLOC_FREE(frame);
228         return ret;
229
230 }
231
232 static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle,
233                                     struct files_struct *fsp, char *list,
234                                     size_t size)
235 {
236         SMB_STRUCT_STAT sbuf;
237         struct file_id id;
238         struct db_context *db;
239         int ret;
240         TALLOC_CTX *frame = talloc_stackframe();
241
242         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
243                                 if (!xattr_tdb_init(-1, frame, &db))
244                                 {
245                                         TALLOC_FREE(frame); return -1;
246                                 });
247
248         if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
249                 TALLOC_FREE(frame);
250                 return -1;
251         }
252
253         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
254
255         ret = xattr_tdb_listattr(db, &id, list, size);
256         TALLOC_FREE(frame);
257         return ret;
258 }
259
260 static int xattr_tdb_removexattr(struct vfs_handle_struct *handle,
261                                  const char *path, const char *name)
262 {
263         struct file_id id;
264         struct db_context *db;
265         int ret;
266         TALLOC_CTX *frame = talloc_stackframe();
267
268         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
269                                 if (!xattr_tdb_init(-1, frame, &db))
270                                 {
271                                         TALLOC_FREE(frame); return -1;
272                                 });
273
274         ret = xattr_tdb_get_file_id(handle, path, &id);
275         if (ret == -1) {
276                 TALLOC_FREE(frame);
277                 return ret;
278         }
279
280         
281         ret = xattr_tdb_removeattr(db, &id, name);
282         TALLOC_FREE(frame);
283         return ret;
284 }
285
286 static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle,
287                                   struct files_struct *fsp, const char *name)
288 {
289         SMB_STRUCT_STAT sbuf;
290         struct file_id id;
291         struct db_context *db;
292         int ret;
293         TALLOC_CTX *frame = talloc_stackframe();
294
295         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
296                                 if (!xattr_tdb_init(-1, frame, &db))
297                                 {
298                                         TALLOC_FREE(frame); return -1;
299                                 });
300
301         if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
302                 TALLOC_FREE(frame);
303                 return -1;
304         }
305
306         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
307
308         ret = xattr_tdb_removeattr(db, &id, name);
309         TALLOC_FREE(frame);
310         return ret;
311 }
312
313 /*
314  * Open the tdb file upon VFS_CONNECT
315  */
316
317 static bool xattr_tdb_init(int snum, TALLOC_CTX *mem_ctx, struct db_context **p_db)
318 {
319         struct db_context *db;
320         const char *dbname;
321         char *def_dbname;
322
323         def_dbname = state_path("xattr.tdb");
324         if (def_dbname == NULL) {
325                 errno = ENOSYS;
326                 return false;
327         }
328
329         dbname = lp_parm_const_string(snum, "xattr_tdb", "file", def_dbname);
330
331         /* now we know dbname is not NULL */
332
333         become_root();
334         db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
335                      DBWRAP_LOCK_ORDER_2, DBWRAP_FLAG_NONE);
336         unbecome_root();
337
338         if (db == NULL) {
339 #if defined(ENOTSUP)
340                 errno = ENOTSUP;
341 #else
342                 errno = ENOSYS;
343 #endif
344                 TALLOC_FREE(def_dbname);
345                 return false;
346         }
347
348         *p_db = db;
349         TALLOC_FREE(def_dbname);
350         return true;
351 }
352
353 static int xattr_tdb_open(vfs_handle_struct *handle,
354                         struct smb_filename *smb_fname,
355                         files_struct *fsp,
356                         int flags,
357                         mode_t mode)
358 {
359         struct db_context *db = NULL;
360         TALLOC_CTX *frame = NULL;
361         int ret;
362
363         fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle,
364                                 smb_fname, fsp,
365                                 flags,
366                                 mode);
367
368         if (fsp->fh->fd < 0) {
369                 return fsp->fh->fd;
370         }
371
372         if ((flags & (O_CREAT|O_EXCL)) != (O_CREAT|O_EXCL)) {
373                 return fsp->fh->fd;
374         }
375
376         /*
377          * We know we used O_CREAT|O_EXCL and it worked.
378          * We must have created the file.
379          */
380
381         ret = SMB_VFS_FSTAT(fsp, &smb_fname->st);
382         if (ret == -1) {
383                 /* Can't happen... */
384                 DBG_WARNING("SMB_VFS_FSTAT failed on file %s (%s)\n",
385                         smb_fname_str_dbg(smb_fname),
386                         strerror(errno));
387                 return -1;
388         }
389         fsp->file_id = SMB_VFS_FILE_ID_CREATE(fsp->conn, &smb_fname->st);
390
391         frame = talloc_stackframe();
392         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
393                                 if (!xattr_tdb_init(-1, frame, &db))
394                                 {
395                                         TALLOC_FREE(frame); return -1;
396                                 });
397
398         xattr_tdb_remove_all_attrs(db, &fsp->file_id);
399         TALLOC_FREE(frame);
400         return fsp->fh->fd;
401 }
402
403 static int xattr_tdb_mkdir(vfs_handle_struct *handle,
404                 const struct smb_filename *smb_fname,
405                 mode_t mode)
406 {
407         struct db_context *db = NULL;
408         TALLOC_CTX *frame = NULL;
409         struct file_id fileid;
410         int ret;
411         struct smb_filename *smb_fname_tmp = NULL;
412
413         ret = SMB_VFS_NEXT_MKDIR(handle, smb_fname, mode);
414         if (ret < 0) {
415                 return ret;
416         }
417
418         frame = talloc_stackframe();
419         smb_fname_tmp = cp_smb_filename(frame, smb_fname);
420         if (smb_fname_tmp == NULL) {
421                 TALLOC_FREE(frame);
422                 errno = ENOMEM;
423                 return -1;
424         }
425
426         /* Always use LSTAT here - we just creaded the directory. */
427         ret = SMB_VFS_LSTAT(handle->conn, smb_fname_tmp);
428         if (ret == -1) {
429                 /* Rename race. Let upper level take care of it. */
430                 TALLOC_FREE(frame);
431                 return -1;
432         }
433         if (!S_ISDIR(smb_fname_tmp->st.st_ex_mode)) {
434                 /* Rename race. Let upper level take care of it. */
435                 TALLOC_FREE(frame);
436                 return -1;
437         }
438
439         fileid = SMB_VFS_FILE_ID_CREATE(handle->conn, &smb_fname_tmp->st);
440
441         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
442                                 if (!xattr_tdb_init(-1, frame, &db))
443                                 {
444                                         TALLOC_FREE(frame); return -1;
445                                 });
446
447         xattr_tdb_remove_all_attrs(db, &fileid);
448         TALLOC_FREE(frame);
449         return 0;
450 }
451
452 /*
453  * On unlink we need to delete the tdb record
454  */
455 static int xattr_tdb_unlink(vfs_handle_struct *handle,
456                             const struct smb_filename *smb_fname)
457 {
458         struct smb_filename *smb_fname_tmp = NULL;
459         struct file_id id;
460         struct db_context *db;
461         int ret = -1;
462         bool remove_record = false;
463         TALLOC_CTX *frame = talloc_stackframe();
464
465         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
466                                 if (!xattr_tdb_init(-1, frame, &db))
467                                 {
468                                         TALLOC_FREE(frame); return -1;
469                                 });
470
471         smb_fname_tmp = cp_smb_filename(frame, smb_fname);
472         if (smb_fname_tmp == NULL) {
473                 TALLOC_FREE(frame);
474                 errno = ENOMEM;
475                 return -1;
476         }
477
478         if (smb_fname_tmp->flags & SMB_FILENAME_POSIX_PATH) {
479                 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_tmp);
480         } else {
481                 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_tmp);
482         }
483         if (ret == -1) {
484                 goto out;
485         }
486
487         if (smb_fname_tmp->st.st_ex_nlink == 1) {
488                 /* Only remove record on last link to file. */
489                 remove_record = true;
490         }
491
492         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
493
494         if (ret == -1) {
495                 goto out;
496         }
497
498         if (!remove_record) {
499                 goto out;
500         }
501
502         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &smb_fname_tmp->st);
503
504         xattr_tdb_remove_all_attrs(db, &id);
505
506  out:
507         TALLOC_FREE(frame);
508         return ret;
509 }
510
511 /*
512  * On rmdir we need to delete the tdb record
513  */
514 static int xattr_tdb_rmdir(vfs_handle_struct *handle,
515                         const struct smb_filename *smb_fname)
516 {
517         SMB_STRUCT_STAT sbuf;
518         struct file_id id;
519         struct db_context *db;
520         int ret;
521         TALLOC_CTX *frame = talloc_stackframe();
522
523         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
524                                 if (!xattr_tdb_init(-1, frame, &db))
525                                 {
526                                         TALLOC_FREE(frame); return -1;
527                                 });
528
529         if (vfs_stat_smb_basename(handle->conn,
530                                 smb_fname,
531                                 &sbuf) == -1) {
532                 TALLOC_FREE(frame);
533                 return -1;
534         }
535
536         ret = SMB_VFS_NEXT_RMDIR(handle, smb_fname);
537
538         if (ret == -1) {
539                 TALLOC_FREE(frame);
540                 return -1;
541         }
542
543         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
544
545         xattr_tdb_remove_all_attrs(db, &id);
546
547         TALLOC_FREE(frame);
548         return 0;
549 }
550
551 /*
552  * Destructor for the VFS private data
553  */
554
555 static void close_xattr_db(void **data)
556 {
557         struct db_context **p_db = (struct db_context **)data;
558         TALLOC_FREE(*p_db);
559 }
560
561 static int xattr_tdb_connect(vfs_handle_struct *handle, const char *service,
562                           const char *user)
563 {
564         char *sname = NULL;
565         int res, snum;
566         struct db_context *db;
567
568         res = SMB_VFS_NEXT_CONNECT(handle, service, user);
569         if (res < 0) {
570                 return res;
571         }
572
573         snum = find_service(talloc_tos(), service, &sname);
574         if (snum == -1 || sname == NULL) {
575                 /*
576                  * Should not happen, but we should not fail just *here*.
577                  */
578                 return 0;
579         }
580
581         if (!xattr_tdb_init(snum, NULL, &db)) {
582                 DEBUG(5, ("Could not init xattr tdb\n"));
583                 lp_do_parameter(snum, "ea support", "False");
584                 return 0;
585         }
586
587         lp_do_parameter(snum, "ea support", "True");
588
589         SMB_VFS_HANDLE_SET_DATA(handle, db, close_xattr_db,
590                                 struct db_context, return -1);
591
592         return 0;
593 }
594
595 static struct vfs_fn_pointers vfs_xattr_tdb_fns = {
596         .getxattr_fn = xattr_tdb_getxattr,
597         .fgetxattr_fn = xattr_tdb_fgetxattr,
598         .setxattr_fn = xattr_tdb_setxattr,
599         .fsetxattr_fn = xattr_tdb_fsetxattr,
600         .listxattr_fn = xattr_tdb_listxattr,
601         .flistxattr_fn = xattr_tdb_flistxattr,
602         .removexattr_fn = xattr_tdb_removexattr,
603         .fremovexattr_fn = xattr_tdb_fremovexattr,
604         .open_fn = xattr_tdb_open,
605         .mkdir_fn = xattr_tdb_mkdir,
606         .unlink_fn = xattr_tdb_unlink,
607         .rmdir_fn = xattr_tdb_rmdir,
608         .connect_fn = xattr_tdb_connect,
609 };
610
611 NTSTATUS vfs_xattr_tdb_init(TALLOC_CTX *);
612 NTSTATUS vfs_xattr_tdb_init(TALLOC_CTX *ctx)
613 {
614         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "xattr_tdb",
615                                 &vfs_xattr_tdb_fns);
616 }