s3:libsmb: allow store_cldap_reply() to work with a ipv6 response
[samba.git] / source3 / modules / vfs_posix_eadb.c
1 /*
2  * Store posix-level xattrs in a tdb (posix:eadb format)
3  *
4  * Copyright (C) Andrew Bartlett, 2011
5  *
6  * Based on vfs_xattr_tdb by
7  * Copyright (C) Volker Lendecke, 2007
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #include "includes.h"
24 #include "system/filesys.h"
25 #include "smbd/smbd.h"
26 #include "librpc/gen_ndr/xattr.h"
27 #include "librpc/gen_ndr/ndr_xattr.h"
28 #include "../librpc/gen_ndr/ndr_netlogon.h"
29 #include <tdb.h>
30 #include "lib/tdb_wrap/tdb_wrap.h"
31 #include "ntvfs/posix/posix_eadb.h"
32 #include "param/param.h"
33 #include "lib/param/loadparm.h"
34
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_VFS
37
38 /*
39  * Worker routine for getxattr and fgetxattr
40  */
41
42 static ssize_t posix_eadb_getattr(struct tdb_wrap *db_ctx,
43                                  const char *fname, int fd,
44                                  const char *name, void *value, size_t size)
45 {
46         ssize_t result = -1;
47         NTSTATUS status;
48         DATA_BLOB blob;
49
50         DEBUG(10, ("posix_eadb_getattr called for file %s/fd %d, name %s\n",
51                    fname, fd, name));
52
53         status = pull_xattr_blob_tdb_raw(db_ctx, talloc_tos(), name, fname, fd, size, &blob);
54
55         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
56                 errno = ENOATTR;
57                 return -1;
58         }
59
60         if (!NT_STATUS_IS_OK(status)) {
61                 DEBUG(10, ("posix_eadb_fetch_attrs failed: %s\n",
62                            nt_errstr(status)));
63                 errno = EINVAL;
64                 return -1;
65         }
66
67         if (blob.length > size) {
68                 errno = ERANGE;
69                 goto fail;
70         }
71
72         memcpy(value, blob.data, blob.length);
73         result = blob.length;
74
75  fail:
76         return result;
77 }
78
79 static ssize_t posix_eadb_fgetxattr(struct vfs_handle_struct *handle,
80                                    struct files_struct *fsp,
81                                    const char *name, void *value, size_t size)
82 {
83         struct tdb_wrap *db;
84
85         SMB_VFS_HANDLE_GET_DATA(handle, db, struct tdb_wrap, return -1);
86
87         return posix_eadb_getattr(db, fsp->fsp_name->base_name, fsp_get_io_fd(fsp), name, value, size);
88 }
89
90 /*
91  * Worker routine for setxattr and fsetxattr
92  */
93
94 static int posix_eadb_setattr(struct tdb_wrap *db_ctx,
95                              const char *fname, int fd, const char *name,
96                              const void *value, size_t size, int flags)
97 {
98         NTSTATUS status;
99         DATA_BLOB data = data_blob_const(value, size);
100
101         DEBUG(10, ("posix_eadb_setattr called for file %s/fd %d, name %s\n",
102                    fname, fd, name));
103
104         status = push_xattr_blob_tdb_raw(db_ctx, name, fname, fd, &data);
105
106         if (!NT_STATUS_IS_OK(status)) {
107                 DEBUG(10, ("push_xattr_blob_tdb_raw failed: %s\n",
108                            nt_errstr(status)));
109                 return -1;
110         }
111
112         return 0;
113 }
114
115 static int posix_eadb_fsetxattr(struct vfs_handle_struct *handle,
116                                struct files_struct *fsp,
117                                const char *name, const void *value,
118                                size_t size, int flags)
119 {
120         struct tdb_wrap *db;
121
122         SMB_VFS_HANDLE_GET_DATA(handle, db, struct tdb_wrap, return -1);
123
124         return posix_eadb_setattr(db, fsp->fsp_name->base_name, fsp_get_io_fd(fsp), name, value, size, flags);
125 }
126
127 /*
128  * Worker routine for listxattr and flistxattr
129  */
130
131 static ssize_t posix_eadb_listattr(struct tdb_wrap *db_ctx,
132                                   const char *fname, int fd, char *list,
133                                   size_t size)
134 {
135         DATA_BLOB blob;
136         NTSTATUS status;
137
138         status = list_posix_eadb_raw(db_ctx, talloc_tos(), fname, fd, &blob);
139
140         if (!NT_STATUS_IS_OK(status)) {
141                 DEBUG(10, ("posix_eadb_fetch_attrs failed: %s\n",
142                            nt_errstr(status)));
143                 errno = EINVAL;
144                 return -1;
145         }
146
147         if (blob.length > size) {
148                 errno = ERANGE;
149                 TALLOC_FREE(blob.data);
150                 return -1;
151         }
152
153         memcpy(list, blob.data, blob.length);
154
155         TALLOC_FREE(blob.data);
156         return blob.length;
157 }
158
159 static ssize_t posix_eadb_flistxattr(struct vfs_handle_struct *handle,
160                                     struct files_struct *fsp, char *list,
161                                     size_t size)
162 {
163         struct tdb_wrap *db;
164
165         SMB_VFS_HANDLE_GET_DATA(handle, db, struct tdb_wrap, return -1);
166
167         return posix_eadb_listattr(db, fsp->fsp_name->base_name, fsp_get_io_fd(fsp), list, size);
168 }
169
170 /*
171  * Worker routine for removexattr and fremovexattr
172  */
173
174 static int posix_eadb_removeattr(struct tdb_wrap *db_ctx,
175                                 const char *fname, int fd, const char *name)
176 {
177         NTSTATUS status;
178
179         status = delete_posix_eadb_raw(db_ctx, name, fname, fd);
180
181         if (!NT_STATUS_IS_OK(status)) {
182                 DEBUG(10, ("delete_posix_eadb_raw failed: %s\n",
183                            nt_errstr(status)));
184                 return -1;
185         }
186         return 0;
187 }
188
189 static int posix_eadb_fremovexattr(struct vfs_handle_struct *handle,
190                                   struct files_struct *fsp, const char *name)
191 {
192         struct tdb_wrap *db;
193
194         SMB_VFS_HANDLE_GET_DATA(handle, db, struct tdb_wrap, return -1);
195
196         return posix_eadb_removeattr(db, fsp->fsp_name->base_name, fsp_get_io_fd(fsp), name);
197 }
198
199 /*
200  * Open the tdb file upon VFS_CONNECT
201  */
202
203 static bool posix_eadb_init(int snum, struct tdb_wrap **p_db)
204 {
205         struct tdb_wrap *db;
206         struct loadparm_context *lp_ctx;
207         const char *eadb = lp_parm_const_string(snum, "posix", "eadb", NULL);
208
209         if (!eadb) {
210                 DEBUG(0, ("Can not use vfs_posix_eadb without posix:eadb set\n"));
211                 return false;
212         }
213
214         lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
215
216         become_root();
217         db = tdb_wrap_open(NULL, eadb, 50000,
218                            lpcfg_tdb_flags(lp_ctx, TDB_DEFAULT),
219                            O_RDWR|O_CREAT, 0600);
220
221         unbecome_root();
222         talloc_unlink(NULL, lp_ctx);
223         /* now we know dbname is not NULL */
224
225         if (db == NULL) {
226 #if defined(ENOTSUP)
227                 errno = ENOTSUP;
228 #else
229                 errno = ENOSYS;
230 #endif
231                 return false;
232         }
233
234         *p_db = db;
235         return true;
236 }
237
238 /*
239  * On unlink we need to delete the tdb record
240  */
241 static int posix_eadb_unlink_internal(vfs_handle_struct *handle,
242                         struct files_struct *dirfsp,
243                         const struct smb_filename *smb_fname,
244                         int flags)
245 {
246         struct smb_filename *full_fname = NULL;
247         struct smb_filename *smb_fname_tmp = NULL;
248         int ret = -1;
249
250         struct tdb_wrap *ea_tdb;
251
252         SMB_VFS_HANDLE_GET_DATA(handle, ea_tdb, struct tdb_wrap, return -1);
253
254         smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
255         if (smb_fname_tmp == NULL) {
256                 errno = ENOMEM;
257                 return -1;
258         }
259
260         /*
261          * TODO: use SMB_VFS_STATX() once we have that.
262          */
263
264         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
265                                                   dirfsp,
266                                                   smb_fname);
267         if (full_fname == NULL) {
268                 goto out;
269         }
270
271         if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
272                 ret = SMB_VFS_NEXT_LSTAT(handle, full_fname);
273         } else {
274                 ret = SMB_VFS_NEXT_STAT(handle, full_fname);
275         }
276         if (ret == -1) {
277                 goto out;
278         }
279         smb_fname_tmp->st = full_fname->st;
280
281         if (smb_fname_tmp->st.st_ex_nlink == 1) {
282                 NTSTATUS status;
283
284                 /* Only remove record on last link to file. */
285
286                 if (tdb_transaction_start(ea_tdb->tdb) != 0) {
287                         ret = -1;
288                         goto out;
289                 }
290
291                 status = unlink_posix_eadb_raw(ea_tdb,
292                                                full_fname->base_name,
293                                                -1);
294                 if (!NT_STATUS_IS_OK(status)) {
295                         tdb_transaction_cancel(ea_tdb->tdb);
296                         ret = -1;
297                         goto out;
298                 }
299         }
300
301         ret = SMB_VFS_NEXT_UNLINKAT(handle,
302                         dirfsp,
303                         smb_fname_tmp,
304                         flags);
305
306         if (ret == -1) {
307                 tdb_transaction_cancel(ea_tdb->tdb);
308                 goto out;
309         } else {
310                 if (tdb_transaction_commit(ea_tdb->tdb) != 0) {
311                         ret = -1;
312                         goto out;
313                 }
314         }
315
316 out:
317         TALLOC_FREE(smb_fname_tmp);
318         TALLOC_FREE(full_fname);
319         return ret;
320 }
321
322 /*
323  * On rmdir we need to delete the tdb record
324  */
325 static int posix_eadb_rmdir_internal(vfs_handle_struct *handle,
326                         struct files_struct *dirfsp,
327                         const struct smb_filename *smb_fname)
328 {
329         NTSTATUS status;
330         struct tdb_wrap *ea_tdb;
331         int ret;
332         struct smb_filename *full_fname = NULL;
333
334         SMB_VFS_HANDLE_GET_DATA(handle, ea_tdb, struct tdb_wrap, return -1);
335
336         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
337                                                   dirfsp,
338                                                   smb_fname);
339         if (full_fname == NULL) {
340                 return -1;
341         }
342
343         if (tdb_transaction_start(ea_tdb->tdb) != 0) {
344                 TALLOC_FREE(full_fname);
345                 return -1;
346         }
347
348         status = unlink_posix_eadb_raw(ea_tdb, full_fname->base_name, -1);
349         TALLOC_FREE(full_fname);
350         if (!NT_STATUS_IS_OK(status)) {
351                 tdb_transaction_cancel(ea_tdb->tdb);
352         }
353
354         ret = SMB_VFS_NEXT_UNLINKAT(handle,
355                                 dirfsp,
356                                 smb_fname,
357                                 AT_REMOVEDIR);
358
359         if (ret == -1) {
360                 tdb_transaction_cancel(ea_tdb->tdb);
361         } else {
362                 if (tdb_transaction_commit(ea_tdb->tdb) != 0) {
363                         return -1;
364                 }
365         }
366
367         return ret;
368 }
369
370 static int posix_eadb_unlinkat(vfs_handle_struct *handle,
371                         struct files_struct *dirfsp,
372                         const struct smb_filename *smb_fname,
373                         int flags)
374 {
375         int ret;
376
377         if (flags & AT_REMOVEDIR) {
378                 ret = posix_eadb_rmdir_internal(handle,
379                                         dirfsp,
380                                         smb_fname);
381         } else {
382                 ret = posix_eadb_unlink_internal(handle,
383                                         dirfsp,
384                                         smb_fname,
385                                         flags);
386         }
387         return ret;
388 }
389
390 /*
391  * Destructor for the VFS private data
392  */
393
394 static void close_xattr_db(void **data)
395 {
396         struct tdb_wrap **p_db = (struct tdb_wrap **)data;
397         TALLOC_FREE(*p_db);
398 }
399
400 static int posix_eadb_connect(vfs_handle_struct *handle, const char *service,
401                           const char *user)
402 {
403         char *sname = NULL;
404         int res, snum;
405         struct tdb_wrap *db;
406
407         res = SMB_VFS_NEXT_CONNECT(handle, service, user);
408         if (res < 0) {
409                 return res;
410         }
411
412         snum = find_service(talloc_tos(), service, &sname);
413         if (snum == -1 || sname == NULL) {
414                 /*
415                  * Should not happen, but we should not fail just *here*.
416                  */
417                 return 0;
418         }
419
420         if (!posix_eadb_init(snum, &db)) {
421                 DEBUG(5, ("Could not init xattr tdb\n"));
422                 lp_do_parameter(snum, "ea support", "False");
423                 return 0;
424         }
425
426         lp_do_parameter(snum, "ea support", "True");
427
428         SMB_VFS_HANDLE_SET_DATA(handle, db, close_xattr_db,
429                                 struct tdb_wrap, return -1);
430
431         return 0;
432 }
433
434 static struct vfs_fn_pointers vfs_posix_eadb_fns = {
435         .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
436         .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
437         .fgetxattr_fn = posix_eadb_fgetxattr,
438         .fsetxattr_fn = posix_eadb_fsetxattr,
439         .flistxattr_fn = posix_eadb_flistxattr,
440         .fremovexattr_fn = posix_eadb_fremovexattr,
441         .unlinkat_fn = posix_eadb_unlinkat,
442         .connect_fn = posix_eadb_connect,
443 };
444
445 static_decl_vfs;
446 NTSTATUS vfs_posix_eadb_init(TALLOC_CTX *ctx)
447 {
448         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "posix_eadb",
449                                 &vfs_posix_eadb_fns);
450 }