Line data Source code
1 : /*
2 : * Store posix-level xattrs in a tdb
3 : *
4 : * Copyright (C) Andrew Bartlett 2011
5 : *
6 : * extracted from vfs_xattr_tdb by
7 : *
8 : * Copyright (C) Volker Lendecke, 2007
9 : *
10 : * This program is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License as published by
12 : * the Free Software Foundation; either version 3 of the License, or
13 : * (at your option) any later version.
14 : *
15 : * This program is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU General Public License
21 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : #include "source3/include/includes.h"
25 : #include "system/filesys.h"
26 : #include "librpc/gen_ndr/xattr.h"
27 : #include "librpc/gen_ndr/ndr_xattr.h"
28 : #include "librpc/gen_ndr/file_id.h"
29 : #include "dbwrap/dbwrap.h"
30 : #include "lib/util/util_tdb.h"
31 : #include "source3/lib/xattr_tdb.h"
32 : #include "source3/lib/file_id.h"
33 :
34 : #undef DBGC_CLASS
35 : #define DBGC_CLASS DBGC_VFS
36 :
37 : /*
38 : * unmarshall tdb_xattrs
39 : */
40 :
41 21198829 : static NTSTATUS xattr_tdb_pull_attrs(TALLOC_CTX *mem_ctx,
42 : const TDB_DATA *data,
43 : struct tdb_xattrs **presult)
44 : {
45 63350 : DATA_BLOB blob;
46 63350 : enum ndr_err_code ndr_err;
47 63350 : struct tdb_xattrs *result;
48 :
49 21198829 : if (!(result = talloc_zero(mem_ctx, struct tdb_xattrs))) {
50 0 : return NT_STATUS_NO_MEMORY;
51 : }
52 :
53 21198829 : if (data->dsize == 0) {
54 159998 : *presult = result;
55 159998 : return NT_STATUS_OK;
56 : }
57 :
58 21038831 : blob = data_blob_const(data->dptr, data->dsize);
59 :
60 21038831 : ndr_err = ndr_pull_struct_blob(&blob, result, result,
61 : (ndr_pull_flags_fn_t)ndr_pull_tdb_xattrs);
62 :
63 21038831 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
64 0 : DEBUG(0, ("ndr_pull_tdb_xattrs failed: %s\n",
65 : ndr_errstr(ndr_err)));
66 0 : TALLOC_FREE(result);
67 0 : return ndr_map_error2ntstatus(ndr_err);
68 : }
69 :
70 21038831 : *presult = result;
71 21038831 : return NT_STATUS_OK;
72 : }
73 :
74 : /*
75 : * marshall tdb_xattrs
76 : */
77 :
78 792654 : static NTSTATUS xattr_tdb_push_attrs(TALLOC_CTX *mem_ctx,
79 : const struct tdb_xattrs *attribs,
80 : TDB_DATA *data)
81 : {
82 2834 : DATA_BLOB blob;
83 2834 : enum ndr_err_code ndr_err;
84 :
85 792654 : ndr_err = ndr_push_struct_blob(&blob, mem_ctx, attribs,
86 : (ndr_push_flags_fn_t)ndr_push_tdb_xattrs);
87 :
88 792654 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
89 0 : DEBUG(0, ("ndr_push_tdb_xattrs failed: %s\n",
90 : ndr_errstr(ndr_err)));
91 0 : return ndr_map_error2ntstatus(ndr_err);
92 : }
93 :
94 792654 : *data = make_tdb_data(blob.data, blob.length);
95 792654 : return NT_STATUS_OK;
96 : }
97 :
98 : /*
99 : * Load tdb_xattrs for a file from the tdb
100 : */
101 :
102 24508790 : static NTSTATUS xattr_tdb_load_attrs(TALLOC_CTX *mem_ctx,
103 : struct db_context *db_ctx,
104 : const struct file_id *id,
105 : struct tdb_xattrs **presult)
106 : {
107 87650 : uint8_t id_buf[16];
108 87650 : NTSTATUS status;
109 87650 : TDB_DATA data;
110 :
111 : /* For backwards compatibility only store the dev/inode. */
112 24508790 : push_file_id_16((char *)id_buf, id);
113 :
114 24508790 : status = dbwrap_fetch(db_ctx, mem_ctx,
115 : make_tdb_data(id_buf, sizeof(id_buf)),
116 : &data);
117 24508790 : if (!NT_STATUS_IS_OK(status)) {
118 4102978 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
119 4102978 : return status;
120 : }
121 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
122 : }
123 :
124 20405812 : status = xattr_tdb_pull_attrs(mem_ctx, &data, presult);
125 20405812 : TALLOC_FREE(data.dptr);
126 20405812 : return status;
127 : }
128 :
129 : /*
130 : * fetch_lock the tdb_ea record for a file
131 : */
132 :
133 1113637 : static struct db_record *xattr_tdb_lock_attrs(TALLOC_CTX *mem_ctx,
134 : struct db_context *db_ctx,
135 : const struct file_id *id)
136 : {
137 3521 : uint8_t id_buf[16];
138 :
139 : /* For backwards compatibility only store the dev/inode. */
140 1113637 : push_file_id_16((char *)id_buf, id);
141 1113637 : return dbwrap_fetch_locked(db_ctx, mem_ctx,
142 : make_tdb_data(id_buf, sizeof(id_buf)));
143 : }
144 :
145 : /*
146 : * Save tdb_xattrs to a previously fetch_locked record
147 : */
148 :
149 792654 : static NTSTATUS xattr_tdb_save_attrs(struct db_record *rec,
150 : const struct tdb_xattrs *attribs)
151 : {
152 792654 : TDB_DATA data = tdb_null;
153 2834 : NTSTATUS status;
154 :
155 792654 : status = xattr_tdb_push_attrs(talloc_tos(), attribs, &data);
156 :
157 792654 : if (!NT_STATUS_IS_OK(status)) {
158 0 : DEBUG(0, ("xattr_tdb_push_attrs failed: %s\n",
159 : nt_errstr(status)));
160 0 : return status;
161 : }
162 :
163 792654 : status = dbwrap_record_store(rec, data, 0);
164 :
165 792654 : TALLOC_FREE(data.dptr);
166 :
167 792654 : return status;
168 : }
169 :
170 : /*
171 : * Worker routine for getxattr and fgetxattr
172 : */
173 :
174 23772886 : ssize_t xattr_tdb_getattr(struct db_context *db_ctx,
175 : TALLOC_CTX *mem_ctx,
176 : const struct file_id *id,
177 : const char *name, DATA_BLOB *blob)
178 : {
179 86579 : struct tdb_xattrs *attribs;
180 86579 : uint32_t i;
181 23772886 : ssize_t result = -1;
182 86579 : NTSTATUS status;
183 23772886 : TALLOC_CTX *frame = talloc_stackframe();
184 86579 : struct file_id_buf buf;
185 :
186 23772886 : DBG_DEBUG("xattr_tdb_getattr called for file %s, name %s\n",
187 : file_id_str_buf(*id, &buf), name);
188 :
189 23772886 : status = xattr_tdb_load_attrs(frame, db_ctx, id, &attribs);
190 :
191 23772886 : if (!NT_STATUS_IS_OK(status)) {
192 4064628 : DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
193 : nt_errstr(status)));
194 4064628 : TALLOC_FREE(frame);
195 4064628 : errno = EINVAL;
196 4064628 : return -1;
197 : }
198 :
199 52791040 : for (i=0; i<attribs->num_eas; i++) {
200 49534979 : if (strcmp(attribs->eas[i].name, name) == 0) {
201 16395721 : break;
202 : }
203 : }
204 :
205 19708258 : if (i == attribs->num_eas) {
206 3256061 : errno = ENOATTR;
207 3256061 : goto fail;
208 : }
209 :
210 16452197 : *blob = attribs->eas[i].value;
211 16452197 : talloc_steal(mem_ctx, blob->data);
212 16452197 : result = attribs->eas[i].value.length;
213 :
214 19708258 : fail:
215 19708258 : TALLOC_FREE(frame);
216 19648777 : return result;
217 : }
218 :
219 : /*
220 : * Worker routine for setxattr and fsetxattr
221 : */
222 :
223 790935 : int xattr_tdb_setattr(struct db_context *db_ctx,
224 : const struct file_id *id, const char *name,
225 : const void *value, size_t size, int flags)
226 : {
227 2623 : NTSTATUS status;
228 2623 : struct db_record *rec;
229 2623 : struct tdb_xattrs *attribs;
230 2623 : uint32_t i;
231 2623 : TDB_DATA data;
232 790935 : TALLOC_CTX *frame = talloc_stackframe();
233 2623 : struct file_id_buf buf;
234 :
235 790935 : DBG_DEBUG("xattr_tdb_setattr called for file %s, name %s\n",
236 : file_id_str_buf(*id, &buf), name);
237 :
238 790935 : rec = xattr_tdb_lock_attrs(frame, db_ctx, id);
239 :
240 790935 : if (rec == NULL) {
241 0 : DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
242 0 : errno = EINVAL;
243 0 : return -1;
244 : }
245 :
246 790935 : data = dbwrap_record_get_value(rec);
247 :
248 790935 : status = xattr_tdb_pull_attrs(rec, &data, &attribs);
249 :
250 790935 : if (!NT_STATUS_IS_OK(status)) {
251 0 : DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
252 : nt_errstr(status)));
253 0 : TALLOC_FREE(frame);
254 0 : return -1;
255 : }
256 :
257 2385007 : for (i=0; i<attribs->num_eas; i++) {
258 1626506 : if (strcmp(attribs->eas[i].name, name) == 0) {
259 32434 : if (flags & XATTR_CREATE) {
260 0 : TALLOC_FREE(frame);
261 0 : errno = EEXIST;
262 0 : return -1;
263 : }
264 32172 : break;
265 : }
266 : }
267 :
268 790935 : if (i == attribs->num_eas) {
269 2361 : struct xattr_EA *tmp;
270 :
271 758501 : if (flags & XATTR_REPLACE) {
272 0 : TALLOC_FREE(frame);
273 0 : errno = ENOATTR;
274 0 : return -1;
275 : }
276 :
277 758501 : tmp = talloc_realloc(
278 : attribs, attribs->eas, struct xattr_EA,
279 : attribs->num_eas+ 1);
280 :
281 758501 : if (tmp == NULL) {
282 0 : DEBUG(0, ("talloc_realloc failed\n"));
283 0 : TALLOC_FREE(frame);
284 0 : errno = ENOMEM;
285 0 : return -1;
286 : }
287 :
288 758501 : attribs->eas = tmp;
289 758501 : attribs->num_eas += 1;
290 : }
291 :
292 790935 : attribs->eas[i].name = name;
293 790935 : attribs->eas[i].value.data = discard_const_p(uint8_t, value);
294 790935 : attribs->eas[i].value.length = size;
295 :
296 790935 : status = xattr_tdb_save_attrs(rec, attribs);
297 :
298 790935 : TALLOC_FREE(frame);
299 :
300 790935 : if (!NT_STATUS_IS_OK(status)) {
301 0 : DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
302 0 : return -1;
303 : }
304 :
305 788312 : return 0;
306 : }
307 :
308 : /*
309 : * Worker routine for listxattr and flistxattr
310 : */
311 :
312 735904 : ssize_t xattr_tdb_listattr(struct db_context *db_ctx,
313 : const struct file_id *id, char *list,
314 : size_t size)
315 : {
316 1071 : NTSTATUS status;
317 1071 : struct tdb_xattrs *attribs;
318 1071 : uint32_t i;
319 735904 : size_t len = 0;
320 735904 : TALLOC_CTX *frame = talloc_stackframe();
321 :
322 735904 : status = xattr_tdb_load_attrs(frame, db_ctx, id, &attribs);
323 :
324 735904 : if (!NT_STATUS_IS_OK(status) &&
325 38309 : !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND))
326 : {
327 0 : DEBUG(0, ("xattr_tdb_fetch_attrs failed: %s\n",
328 : nt_errstr(status)));
329 0 : errno = EINVAL;
330 0 : TALLOC_FREE(frame);
331 0 : return -1;
332 : }
333 :
334 735904 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
335 38350 : TALLOC_FREE(frame);
336 38350 : return 0;
337 : }
338 :
339 697554 : DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n",
340 : attribs->num_eas));
341 :
342 4137830 : for (i=0; i<attribs->num_eas; i++) {
343 5843 : size_t tmp;
344 :
345 3440276 : DEBUG(10, ("xattr_tdb_listattr: xattrs[i].name: %s\n",
346 : attribs->eas[i].name));
347 :
348 3440276 : tmp = strlen(attribs->eas[i].name);
349 :
350 : /*
351 : * Try to protect against overflow
352 : */
353 :
354 3440276 : if (len + (tmp+1) < len) {
355 0 : TALLOC_FREE(frame);
356 0 : errno = EINVAL;
357 0 : return -1;
358 : }
359 :
360 : /*
361 : * Take care of the terminating NULL
362 : */
363 3440276 : len += (tmp + 1);
364 : }
365 :
366 697554 : if (len > size) {
367 0 : TALLOC_FREE(frame);
368 0 : errno = ERANGE;
369 0 : return len;
370 : }
371 :
372 696524 : len = 0;
373 :
374 4137830 : for (i=0; i<attribs->num_eas; i++) {
375 3440276 : strlcpy(list+len, attribs->eas[i].name,
376 : size-len);
377 3440276 : len += (strlen(attribs->eas[i].name) + 1);
378 : }
379 :
380 697554 : TALLOC_FREE(frame);
381 697554 : return len;
382 : }
383 :
384 : /*
385 : * Worker routine for removexattr and fremovexattr
386 : */
387 :
388 2082 : int xattr_tdb_removeattr(struct db_context *db_ctx,
389 : const struct file_id *id, const char *name)
390 : {
391 216 : NTSTATUS status;
392 216 : struct db_record *rec;
393 216 : struct tdb_xattrs *attribs;
394 216 : uint32_t i;
395 216 : TDB_DATA value;
396 :
397 2082 : rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
398 :
399 2082 : if (rec == NULL) {
400 0 : DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
401 0 : errno = EINVAL;
402 0 : return -1;
403 : }
404 :
405 2082 : value = dbwrap_record_get_value(rec);
406 :
407 2082 : status = xattr_tdb_pull_attrs(rec, &value, &attribs);
408 :
409 2082 : if (!NT_STATUS_IS_OK(status)) {
410 0 : DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
411 : nt_errstr(status)));
412 0 : TALLOC_FREE(rec);
413 0 : return -1;
414 : }
415 :
416 10091 : for (i=0; i<attribs->num_eas; i++) {
417 9728 : if (strcmp(attribs->eas[i].name, name) == 0) {
418 1508 : break;
419 : }
420 : }
421 :
422 2082 : if (i == attribs->num_eas) {
423 363 : TALLOC_FREE(rec);
424 363 : errno = ENOATTR;
425 363 : return -1;
426 : }
427 :
428 1719 : attribs->eas[i] =
429 1719 : attribs->eas[attribs->num_eas-1];
430 1719 : attribs->num_eas -= 1;
431 :
432 1719 : if (attribs->num_eas == 0) {
433 0 : dbwrap_record_delete(rec);
434 0 : TALLOC_FREE(rec);
435 0 : return 0;
436 : }
437 :
438 1719 : status = xattr_tdb_save_attrs(rec, attribs);
439 :
440 1719 : TALLOC_FREE(rec);
441 :
442 1719 : if (!NT_STATUS_IS_OK(status)) {
443 0 : DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
444 0 : return -1;
445 : }
446 :
447 1508 : return 0;
448 : }
449 :
450 : /*
451 : * Worker routine for unlink and rmdir
452 : */
453 :
454 320620 : void xattr_tdb_remove_all_attrs(struct db_context *db_ctx,
455 : const struct file_id *id)
456 : {
457 682 : struct db_record *rec;
458 320620 : rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
459 :
460 : /*
461 : * If rec == NULL there's not much we can do about it
462 : */
463 :
464 320620 : if (rec != NULL) {
465 320620 : dbwrap_record_delete(rec);
466 320620 : TALLOC_FREE(rec);
467 : }
468 320620 : }
|