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