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