Line data Source code
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 0 : 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 0 : ssize_t result = -1;
47 : NTSTATUS status;
48 : DATA_BLOB blob;
49 :
50 0 : DEBUG(10, ("posix_eadb_getattr called for file %s/fd %d, name %s\n",
51 : fname, fd, name));
52 :
53 0 : status = pull_xattr_blob_tdb_raw(db_ctx, talloc_tos(), name, fname, fd, size, &blob);
54 :
55 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
56 0 : errno = ENOATTR;
57 0 : return -1;
58 : }
59 :
60 0 : if (!NT_STATUS_IS_OK(status)) {
61 0 : DEBUG(10, ("posix_eadb_fetch_attrs failed: %s\n",
62 : nt_errstr(status)));
63 0 : errno = EINVAL;
64 0 : return -1;
65 : }
66 :
67 0 : if (blob.length > size) {
68 0 : errno = ERANGE;
69 0 : goto fail;
70 : }
71 :
72 0 : memcpy(value, blob.data, blob.length);
73 0 : result = blob.length;
74 :
75 0 : fail:
76 0 : return result;
77 : }
78 :
79 0 : 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 0 : SMB_VFS_HANDLE_GET_DATA(handle, db, struct tdb_wrap, return -1);
86 :
87 0 : 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 0 : 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 0 : DATA_BLOB data = data_blob_const(value, size);
100 :
101 0 : DEBUG(10, ("posix_eadb_setattr called for file %s/fd %d, name %s\n",
102 : fname, fd, name));
103 :
104 0 : status = push_xattr_blob_tdb_raw(db_ctx, name, fname, fd, &data);
105 :
106 0 : if (!NT_STATUS_IS_OK(status)) {
107 0 : DEBUG(10, ("push_xattr_blob_tdb_raw failed: %s\n",
108 : nt_errstr(status)));
109 0 : return -1;
110 : }
111 :
112 0 : return 0;
113 : }
114 :
115 0 : 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 0 : SMB_VFS_HANDLE_GET_DATA(handle, db, struct tdb_wrap, return -1);
123 :
124 0 : 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 0 : 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 0 : status = list_posix_eadb_raw(db_ctx, talloc_tos(), fname, fd, &blob);
139 :
140 0 : if (!NT_STATUS_IS_OK(status)) {
141 0 : DEBUG(10, ("posix_eadb_fetch_attrs failed: %s\n",
142 : nt_errstr(status)));
143 0 : errno = EINVAL;
144 0 : return -1;
145 : }
146 :
147 0 : if (blob.length > size) {
148 0 : errno = ERANGE;
149 0 : TALLOC_FREE(blob.data);
150 0 : return -1;
151 : }
152 :
153 0 : memcpy(list, blob.data, blob.length);
154 :
155 0 : TALLOC_FREE(blob.data);
156 0 : return blob.length;
157 : }
158 :
159 0 : 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 0 : SMB_VFS_HANDLE_GET_DATA(handle, db, struct tdb_wrap, return -1);
166 :
167 0 : 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 0 : 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 0 : status = delete_posix_eadb_raw(db_ctx, name, fname, fd);
180 :
181 0 : if (!NT_STATUS_IS_OK(status)) {
182 0 : DEBUG(10, ("delete_posix_eadb_raw failed: %s\n",
183 : nt_errstr(status)));
184 0 : return -1;
185 : }
186 0 : return 0;
187 : }
188 :
189 0 : 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 0 : SMB_VFS_HANDLE_GET_DATA(handle, db, struct tdb_wrap, return -1);
195 :
196 0 : 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 0 : 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 0 : const char *eadb = lp_parm_const_string(snum, "posix", "eadb", NULL);
208 :
209 0 : if (!eadb) {
210 0 : DEBUG(0, ("Can not use vfs_posix_eadb without posix:eadb set\n"));
211 0 : return false;
212 : }
213 :
214 0 : lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
215 :
216 0 : become_root();
217 0 : db = tdb_wrap_open(NULL, eadb, 50000,
218 : lpcfg_tdb_flags(lp_ctx, TDB_DEFAULT),
219 : O_RDWR|O_CREAT, 0600);
220 :
221 0 : unbecome_root();
222 0 : talloc_unlink(NULL, lp_ctx);
223 : /* now we know dbname is not NULL */
224 :
225 0 : if (db == NULL) {
226 : #if defined(ENOTSUP)
227 0 : errno = ENOTSUP;
228 : #else
229 : errno = ENOSYS;
230 : #endif
231 0 : return false;
232 : }
233 :
234 0 : *p_db = db;
235 0 : return true;
236 : }
237 :
238 : /*
239 : * On unlink we need to delete the tdb record
240 : */
241 0 : 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 0 : struct smb_filename *full_fname = NULL;
247 0 : struct smb_filename *smb_fname_tmp = NULL;
248 0 : int ret = -1;
249 :
250 : struct tdb_wrap *ea_tdb;
251 :
252 0 : SMB_VFS_HANDLE_GET_DATA(handle, ea_tdb, struct tdb_wrap, return -1);
253 :
254 0 : smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
255 0 : if (smb_fname_tmp == NULL) {
256 0 : errno = ENOMEM;
257 0 : return -1;
258 : }
259 :
260 : /*
261 : * TODO: use SMB_VFS_STATX() once we have that.
262 : */
263 :
264 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
265 : dirfsp,
266 : smb_fname);
267 0 : if (full_fname == NULL) {
268 0 : goto out;
269 : }
270 :
271 0 : if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
272 0 : ret = SMB_VFS_NEXT_LSTAT(handle, full_fname);
273 : } else {
274 0 : ret = SMB_VFS_NEXT_STAT(handle, full_fname);
275 : }
276 0 : if (ret == -1) {
277 0 : goto out;
278 : }
279 0 : smb_fname_tmp->st = full_fname->st;
280 :
281 0 : if (smb_fname_tmp->st.st_ex_nlink == 1) {
282 : NTSTATUS status;
283 :
284 : /* Only remove record on last link to file. */
285 :
286 0 : if (tdb_transaction_start(ea_tdb->tdb) != 0) {
287 0 : ret = -1;
288 0 : goto out;
289 : }
290 :
291 0 : status = unlink_posix_eadb_raw(ea_tdb,
292 0 : full_fname->base_name,
293 : -1);
294 0 : if (!NT_STATUS_IS_OK(status)) {
295 0 : tdb_transaction_cancel(ea_tdb->tdb);
296 0 : ret = -1;
297 0 : goto out;
298 : }
299 : }
300 :
301 0 : ret = SMB_VFS_NEXT_UNLINKAT(handle,
302 : dirfsp,
303 : smb_fname_tmp,
304 : flags);
305 :
306 0 : if (ret == -1) {
307 0 : tdb_transaction_cancel(ea_tdb->tdb);
308 0 : goto out;
309 : } else {
310 0 : if (tdb_transaction_commit(ea_tdb->tdb) != 0) {
311 0 : ret = -1;
312 0 : goto out;
313 : }
314 : }
315 :
316 0 : out:
317 0 : TALLOC_FREE(smb_fname_tmp);
318 0 : TALLOC_FREE(full_fname);
319 0 : return ret;
320 : }
321 :
322 : /*
323 : * On rmdir we need to delete the tdb record
324 : */
325 0 : 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 0 : struct smb_filename *full_fname = NULL;
333 :
334 0 : SMB_VFS_HANDLE_GET_DATA(handle, ea_tdb, struct tdb_wrap, return -1);
335 :
336 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
337 : dirfsp,
338 : smb_fname);
339 0 : if (full_fname == NULL) {
340 0 : return -1;
341 : }
342 :
343 0 : if (tdb_transaction_start(ea_tdb->tdb) != 0) {
344 0 : TALLOC_FREE(full_fname);
345 0 : return -1;
346 : }
347 :
348 0 : status = unlink_posix_eadb_raw(ea_tdb, full_fname->base_name, -1);
349 0 : TALLOC_FREE(full_fname);
350 0 : if (!NT_STATUS_IS_OK(status)) {
351 0 : tdb_transaction_cancel(ea_tdb->tdb);
352 : }
353 :
354 0 : ret = SMB_VFS_NEXT_UNLINKAT(handle,
355 : dirfsp,
356 : smb_fname,
357 : AT_REMOVEDIR);
358 :
359 0 : if (ret == -1) {
360 0 : tdb_transaction_cancel(ea_tdb->tdb);
361 : } else {
362 0 : if (tdb_transaction_commit(ea_tdb->tdb) != 0) {
363 0 : return -1;
364 : }
365 : }
366 :
367 0 : return ret;
368 : }
369 :
370 0 : 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 0 : if (flags & AT_REMOVEDIR) {
378 0 : ret = posix_eadb_rmdir_internal(handle,
379 : dirfsp,
380 : smb_fname);
381 : } else {
382 0 : ret = posix_eadb_unlink_internal(handle,
383 : dirfsp,
384 : smb_fname,
385 : flags);
386 : }
387 0 : return ret;
388 : }
389 :
390 : /*
391 : * Destructor for the VFS private data
392 : */
393 :
394 0 : static void close_xattr_db(void **data)
395 : {
396 0 : struct tdb_wrap **p_db = (struct tdb_wrap **)data;
397 0 : TALLOC_FREE(*p_db);
398 0 : }
399 :
400 0 : static int posix_eadb_connect(vfs_handle_struct *handle, const char *service,
401 : const char *user)
402 : {
403 0 : char *sname = NULL;
404 : int res, snum;
405 : struct tdb_wrap *db;
406 :
407 0 : res = SMB_VFS_NEXT_CONNECT(handle, service, user);
408 0 : if (res < 0) {
409 0 : return res;
410 : }
411 :
412 0 : snum = find_service(talloc_tos(), service, &sname);
413 0 : if (snum == -1 || sname == NULL) {
414 : /*
415 : * Should not happen, but we should not fail just *here*.
416 : */
417 0 : return 0;
418 : }
419 :
420 0 : if (!posix_eadb_init(snum, &db)) {
421 0 : DEBUG(5, ("Could not init xattr tdb\n"));
422 0 : lp_do_parameter(snum, "ea support", "False");
423 0 : return 0;
424 : }
425 :
426 0 : lp_do_parameter(snum, "ea support", "True");
427 :
428 0 : SMB_VFS_HANDLE_SET_DATA(handle, db, close_xattr_db,
429 : struct tdb_wrap, return -1);
430 :
431 0 : 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 27 : NTSTATUS vfs_posix_eadb_init(TALLOC_CTX *ctx)
447 : {
448 27 : return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "posix_eadb",
449 : &vfs_posix_eadb_fns);
450 : }
|