s3-xattr_tdb: Be nice to xattr_tdb_getxattr callers, return the full blob
[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  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "system/filesys.h"
22 #include "smbd/smbd.h"
23 #include "dbwrap/dbwrap.h"
24 #include "dbwrap/dbwrap_open.h"
25 #include "source3/lib/xattr_tdb.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_VFS
29
30 static ssize_t xattr_tdb_getxattr(struct vfs_handle_struct *handle,
31                                   const char *path, const char *name,
32                                   void *value, size_t size)
33 {
34         SMB_STRUCT_STAT sbuf;
35         struct file_id id;
36         struct db_context *db;
37         ssize_t xattr_size;
38         DATA_BLOB blob;
39         TALLOC_CTX *frame = talloc_stackframe();
40         if (!frame) {
41                 errno = ENOMEM;
42                 return -1;
43         }
44
45         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
46
47         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
48                 TALLOC_FREE(frame);
49                 return -1;
50         }
51
52         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
53
54         xattr_size = xattr_tdb_getattr(db, frame, &id, name, &blob);
55         if (xattr_size < 0) {
56                 TALLOC_FREE(frame);
57                 return -1;
58         }
59         if (blob.length > size) {
60                 TALLOC_FREE(frame);
61                 errno = ERANGE;
62                 return -1;
63         }
64         memcpy(value, blob.data, size);
65         return xattr_size;
66 }
67
68 static ssize_t xattr_tdb_fgetxattr(struct vfs_handle_struct *handle,
69                                    struct files_struct *fsp,
70                                    const char *name, void *value, size_t size)
71 {
72         SMB_STRUCT_STAT sbuf;
73         struct file_id id;
74         struct db_context *db;
75         ssize_t xattr_size;
76         DATA_BLOB blob;
77         TALLOC_CTX *frame = talloc_stackframe();
78         if (!frame) {
79                 errno = ENOMEM;
80                 return -1;
81         }
82
83         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
84
85         if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
86                 TALLOC_FREE(frame);
87                 return -1;
88         }
89
90         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
91
92         xattr_size = xattr_tdb_getattr(db, frame, &id, name, &blob);
93         if (xattr_size < 0) {
94                 TALLOC_FREE(frame);
95                 return -1;
96         }
97         if (blob.length > size) {
98                 TALLOC_FREE(frame);
99                 errno = ERANGE;
100                 return -1;
101         }
102         memcpy(value, blob.data, size);
103         TALLOC_FREE(frame);
104         return xattr_size;
105 }
106
107 static int xattr_tdb_setxattr(struct vfs_handle_struct *handle,
108                               const char *path, const char *name,
109                               const void *value, size_t size, int flags)
110 {
111         SMB_STRUCT_STAT sbuf;
112         struct file_id id;
113         struct db_context *db;
114
115         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
116
117         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
118                 return -1;
119         }
120
121         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
122
123         return xattr_tdb_setattr(db, &id, name, value, size, flags);
124 }
125
126 static int xattr_tdb_fsetxattr(struct vfs_handle_struct *handle,
127                                struct files_struct *fsp,
128                                const char *name, const void *value,
129                                size_t size, int flags)
130 {
131         SMB_STRUCT_STAT sbuf;
132         struct file_id id;
133         struct db_context *db;
134
135         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
136
137         if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
138                 return -1;
139         }
140
141         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
142
143         return xattr_tdb_setattr(db, &id, name, value, size, flags);
144 }
145
146 static ssize_t xattr_tdb_listxattr(struct vfs_handle_struct *handle,
147                                    const char *path, char *list, size_t size)
148 {
149         SMB_STRUCT_STAT sbuf;
150         struct file_id id;
151         struct db_context *db;
152
153         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
154
155         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
156                 return -1;
157         }
158
159         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
160
161         return xattr_tdb_listattr(db, &id, list, size);
162 }
163
164 static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle,
165                                     struct files_struct *fsp, char *list,
166                                     size_t size)
167 {
168         SMB_STRUCT_STAT sbuf;
169         struct file_id id;
170         struct db_context *db;
171
172         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
173
174         if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
175                 return -1;
176         }
177
178         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
179
180         return xattr_tdb_listattr(db, &id, list, size);
181 }
182
183 static int xattr_tdb_removexattr(struct vfs_handle_struct *handle,
184                                  const char *path, const char *name)
185 {
186         SMB_STRUCT_STAT sbuf;
187         struct file_id id;
188         struct db_context *db;
189
190         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
191
192         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
193                 return -1;
194         }
195
196         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
197
198         return xattr_tdb_removeattr(db, &id, name);
199 }
200
201 static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle,
202                                   struct files_struct *fsp, const char *name)
203 {
204         SMB_STRUCT_STAT sbuf;
205         struct file_id id;
206         struct db_context *db;
207
208         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
209
210         if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
211                 return -1;
212         }
213
214         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
215
216         return xattr_tdb_removeattr(db, &id, name);
217 }
218
219 /*
220  * Open the tdb file upon VFS_CONNECT
221  */
222
223 static bool xattr_tdb_init(int snum, struct db_context **p_db)
224 {
225         struct db_context *db;
226         const char *dbname;
227         char *def_dbname;
228
229         def_dbname = state_path("xattr.tdb");
230         if (def_dbname == NULL) {
231                 errno = ENOSYS;
232                 return false;
233         }
234
235         dbname = lp_parm_const_string(snum, "xattr_tdb", "file", def_dbname);
236
237         /* now we know dbname is not NULL */
238
239         become_root();
240         db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
241                      DBWRAP_LOCK_ORDER_2);
242         unbecome_root();
243
244         if (db == NULL) {
245 #if defined(ENOTSUP)
246                 errno = ENOTSUP;
247 #else
248                 errno = ENOSYS;
249 #endif
250                 TALLOC_FREE(def_dbname);
251                 return false;
252         }
253
254         *p_db = db;
255         TALLOC_FREE(def_dbname);
256         return true;
257 }
258
259 /*
260  * On unlink we need to delete the tdb record
261  */
262 static int xattr_tdb_unlink(vfs_handle_struct *handle,
263                             const struct smb_filename *smb_fname)
264 {
265         struct smb_filename *smb_fname_tmp = NULL;
266         struct file_id id;
267         struct db_context *db;
268         NTSTATUS status;
269         int ret = -1;
270         bool remove_record = false;
271
272         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
273
274         status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
275         if (!NT_STATUS_IS_OK(status)) {
276                 errno = map_errno_from_nt_status(status);
277                 return -1;
278         }
279
280         if (lp_posix_pathnames()) {
281                 ret = SMB_VFS_LSTAT(handle->conn, smb_fname_tmp);
282         } else {
283                 ret = SMB_VFS_STAT(handle->conn, smb_fname_tmp);
284         }
285         if (ret == -1) {
286                 goto out;
287         }
288
289         if (smb_fname_tmp->st.st_ex_nlink == 1) {
290                 /* Only remove record on last link to file. */
291                 remove_record = true;
292         }
293
294         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
295
296         if (ret == -1) {
297                 goto out;
298         }
299
300         if (!remove_record) {
301                 goto out;
302         }
303
304         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &smb_fname_tmp->st);
305
306         xattr_tdb_remove_all_attrs(db, &id);
307
308  out:
309         TALLOC_FREE(smb_fname_tmp);
310         return ret;
311 }
312
313 /*
314  * On rmdir we need to delete the tdb record
315  */
316 static int xattr_tdb_rmdir(vfs_handle_struct *handle, const char *path)
317 {
318         SMB_STRUCT_STAT sbuf;
319         struct file_id id;
320         struct db_context *db;
321         int ret;
322
323         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
324
325         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
326                 return -1;
327         }
328
329         ret = SMB_VFS_NEXT_RMDIR(handle, path);
330
331         if (ret == -1) {
332                 return -1;
333         }
334
335         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
336
337         xattr_tdb_remove_all_attrs(db, &id);
338
339         return 0;
340 }
341
342 /*
343  * Destructor for the VFS private data
344  */
345
346 static void close_xattr_db(void **data)
347 {
348         struct db_context **p_db = (struct db_context **)data;
349         TALLOC_FREE(*p_db);
350 }
351
352 static int xattr_tdb_connect(vfs_handle_struct *handle, const char *service,
353                           const char *user)
354 {
355         char *sname = NULL;
356         int res, snum;
357         struct db_context *db;
358
359         res = SMB_VFS_NEXT_CONNECT(handle, service, user);
360         if (res < 0) {
361                 return res;
362         }
363
364         snum = find_service(talloc_tos(), service, &sname);
365         if (snum == -1 || sname == NULL) {
366                 /*
367                  * Should not happen, but we should not fail just *here*.
368                  */
369                 return 0;
370         }
371
372         if (!xattr_tdb_init(snum, &db)) {
373                 DEBUG(5, ("Could not init xattr tdb\n"));
374                 lp_do_parameter(snum, "ea support", "False");
375                 return 0;
376         }
377
378         lp_do_parameter(snum, "ea support", "True");
379
380         SMB_VFS_HANDLE_SET_DATA(handle, db, close_xattr_db,
381                                 struct db_context, return -1);
382
383         return 0;
384 }
385
386 static struct vfs_fn_pointers vfs_xattr_tdb_fns = {
387         .getxattr_fn = xattr_tdb_getxattr,
388         .fgetxattr_fn = xattr_tdb_fgetxattr,
389         .setxattr_fn = xattr_tdb_setxattr,
390         .fsetxattr_fn = xattr_tdb_fsetxattr,
391         .listxattr_fn = xattr_tdb_listxattr,
392         .flistxattr_fn = xattr_tdb_flistxattr,
393         .removexattr_fn = xattr_tdb_removexattr,
394         .fremovexattr_fn = xattr_tdb_fremovexattr,
395         .unlink_fn = xattr_tdb_unlink,
396         .rmdir_fn = xattr_tdb_rmdir,
397         .connect_fn = xattr_tdb_connect,
398 };
399
400 NTSTATUS vfs_xattr_tdb_init(void);
401 NTSTATUS vfs_xattr_tdb_init(void)
402 {
403         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "xattr_tdb",
404                                 &vfs_xattr_tdb_fns);
405 }