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