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 212826 : static NTSTATUS xattr_tdb_pull_attrs(TALLOC_CTX *mem_ctx,
42 : const TDB_DATA *data,
43 : struct tdb_xattrs **presult)
44 : {
45 : DATA_BLOB blob;
46 : enum ndr_err_code ndr_err;
47 : struct tdb_xattrs *result;
48 :
49 212826 : if (!(result = talloc_zero(mem_ctx, struct tdb_xattrs))) {
50 0 : return NT_STATUS_NO_MEMORY;
51 : }
52 :
53 212826 : if (data->dsize == 0) {
54 2036 : *presult = result;
55 2036 : return NT_STATUS_OK;
56 : }
57 :
58 210790 : blob = data_blob_const(data->dptr, data->dsize);
59 :
60 210790 : ndr_err = ndr_pull_struct_blob(&blob, result, result,
61 : (ndr_pull_flags_fn_t)ndr_pull_tdb_xattrs);
62 :
63 210790 : 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 210790 : *presult = result;
71 210790 : return NT_STATUS_OK;
72 : }
73 :
74 : /*
75 : * marshall tdb_xattrs
76 : */
77 :
78 10361 : static NTSTATUS xattr_tdb_push_attrs(TALLOC_CTX *mem_ctx,
79 : const struct tdb_xattrs *attribs,
80 : TDB_DATA *data)
81 : {
82 : DATA_BLOB blob;
83 : enum ndr_err_code ndr_err;
84 :
85 10361 : ndr_err = ndr_push_struct_blob(&blob, mem_ctx, attribs,
86 : (ndr_push_flags_fn_t)ndr_push_tdb_xattrs);
87 :
88 10361 : 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 10361 : *data = make_tdb_data(blob.data, blob.length);
95 10361 : return NT_STATUS_OK;
96 : }
97 :
98 : /*
99 : * Load tdb_xattrs for a file from the tdb
100 : */
101 :
102 518839 : 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 : uint8_t id_buf[16];
108 : NTSTATUS status;
109 : TDB_DATA data;
110 :
111 : /* For backwards compatibility only store the dev/inode. */
112 518839 : push_file_id_16((char *)id_buf, id);
113 :
114 518839 : status = dbwrap_fetch(db_ctx, mem_ctx,
115 : make_tdb_data(id_buf, sizeof(id_buf)),
116 : &data);
117 518839 : if (!NT_STATUS_IS_OK(status)) {
118 316404 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
119 316404 : return status;
120 : }
121 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
122 : }
123 :
124 202435 : status = xattr_tdb_pull_attrs(mem_ctx, &data, presult);
125 202435 : TALLOC_FREE(data.dptr);
126 202435 : return status;
127 : }
128 :
129 : /*
130 : * fetch_lock the tdb_ea record for a file
131 : */
132 :
133 13539 : 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 : uint8_t id_buf[16];
138 :
139 : /* For backwards compatibility only store the dev/inode. */
140 13539 : push_file_id_16((char *)id_buf, id);
141 13539 : 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 10361 : static NTSTATUS xattr_tdb_save_attrs(struct db_record *rec,
150 : const struct tdb_xattrs *attribs)
151 : {
152 10361 : TDB_DATA data = tdb_null;
153 : NTSTATUS status;
154 :
155 10361 : status = xattr_tdb_push_attrs(talloc_tos(), attribs, &data);
156 :
157 10361 : 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 10361 : status = dbwrap_record_store(rec, data, 0);
164 :
165 10361 : TALLOC_FREE(data.dptr);
166 :
167 10361 : return status;
168 : }
169 :
170 : /*
171 : * Worker routine for getxattr and fgetxattr
172 : */
173 :
174 508479 : 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 : struct tdb_xattrs *attribs;
180 : uint32_t i;
181 508479 : ssize_t result = -1;
182 : NTSTATUS status;
183 508479 : TALLOC_CTX *frame = talloc_stackframe();
184 : struct file_id_buf buf;
185 :
186 508479 : DBG_DEBUG("xattr_tdb_getattr called for file %s, name %s\n",
187 : file_id_str_buf(*id, &buf), name);
188 :
189 508479 : status = xattr_tdb_load_attrs(frame, db_ctx, id, &attribs);
190 :
191 508479 : if (!NT_STATUS_IS_OK(status)) {
192 311066 : DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
193 : nt_errstr(status)));
194 311066 : TALLOC_FREE(frame);
195 311066 : errno = EINVAL;
196 311066 : return -1;
197 : }
198 :
199 500532 : for (i=0; i<attribs->num_eas; i++) {
200 448933 : if (strcmp(attribs->eas[i].name, name) == 0) {
201 145814 : break;
202 : }
203 : }
204 :
205 197413 : if (i == attribs->num_eas) {
206 51599 : errno = ENOATTR;
207 51599 : goto fail;
208 : }
209 :
210 145814 : *blob = attribs->eas[i].value;
211 145814 : talloc_steal(mem_ctx, blob->data);
212 145814 : result = attribs->eas[i].value.length;
213 :
214 197413 : fail:
215 197413 : TALLOC_FREE(frame);
216 197413 : return result;
217 : }
218 :
219 : /*
220 : * Worker routine for setxattr and fsetxattr
221 : */
222 :
223 10353 : 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 : NTSTATUS status;
228 : struct db_record *rec;
229 : struct tdb_xattrs *attribs;
230 : uint32_t i;
231 : TDB_DATA data;
232 10353 : TALLOC_CTX *frame = talloc_stackframe();
233 : struct file_id_buf buf;
234 :
235 10353 : DBG_DEBUG("xattr_tdb_setattr called for file %s, name %s\n",
236 : file_id_str_buf(*id, &buf), name);
237 :
238 10353 : rec = xattr_tdb_lock_attrs(frame, db_ctx, id);
239 :
240 10353 : if (rec == NULL) {
241 0 : DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
242 0 : errno = EINVAL;
243 0 : return -1;
244 : }
245 :
246 10353 : data = dbwrap_record_get_value(rec);
247 :
248 10353 : status = xattr_tdb_pull_attrs(rec, &data, &attribs);
249 :
250 10353 : 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 29188 : for (i=0; i<attribs->num_eas; i++) {
258 20138 : if (strcmp(attribs->eas[i].name, name) == 0) {
259 1303 : if (flags & XATTR_CREATE) {
260 0 : TALLOC_FREE(frame);
261 0 : errno = EEXIST;
262 0 : return -1;
263 : }
264 1303 : break;
265 : }
266 : }
267 :
268 10353 : if (i == attribs->num_eas) {
269 : struct xattr_EA *tmp;
270 :
271 9050 : if (flags & XATTR_REPLACE) {
272 0 : TALLOC_FREE(frame);
273 0 : errno = ENOATTR;
274 0 : return -1;
275 : }
276 :
277 9050 : tmp = talloc_realloc(
278 : attribs, attribs->eas, struct xattr_EA,
279 : attribs->num_eas+ 1);
280 :
281 9050 : 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 9050 : attribs->eas = tmp;
289 9050 : attribs->num_eas += 1;
290 : }
291 :
292 10353 : attribs->eas[i].name = name;
293 10353 : attribs->eas[i].value.data = discard_const_p(uint8_t, value);
294 10353 : attribs->eas[i].value.length = size;
295 :
296 10353 : status = xattr_tdb_save_attrs(rec, attribs);
297 :
298 10353 : TALLOC_FREE(frame);
299 :
300 10353 : if (!NT_STATUS_IS_OK(status)) {
301 0 : DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
302 0 : return -1;
303 : }
304 :
305 10353 : return 0;
306 : }
307 :
308 : /*
309 : * Worker routine for listxattr and flistxattr
310 : */
311 :
312 10360 : ssize_t xattr_tdb_listattr(struct db_context *db_ctx,
313 : const struct file_id *id, char *list,
314 : size_t size)
315 : {
316 : NTSTATUS status;
317 : struct tdb_xattrs *attribs;
318 : uint32_t i;
319 10360 : size_t len = 0;
320 10360 : TALLOC_CTX *frame = talloc_stackframe();
321 :
322 10360 : status = xattr_tdb_load_attrs(frame, db_ctx, id, &attribs);
323 :
324 13266 : if (!NT_STATUS_IS_OK(status) &&
325 5338 : !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 10360 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
335 5338 : TALLOC_FREE(frame);
336 5338 : return 0;
337 : }
338 :
339 5022 : DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n",
340 : attribs->num_eas));
341 :
342 26875 : for (i=0; i<attribs->num_eas; i++) {
343 : size_t tmp;
344 :
345 21853 : DEBUG(10, ("xattr_tdb_listattr: xattrs[i].name: %s\n",
346 : attribs->eas[i].name));
347 :
348 21853 : tmp = strlen(attribs->eas[i].name);
349 :
350 : /*
351 : * Try to protect against overflow
352 : */
353 :
354 21853 : 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 21853 : len += (tmp + 1);
364 : }
365 :
366 5022 : if (len > size) {
367 0 : TALLOC_FREE(frame);
368 0 : errno = ERANGE;
369 0 : return len;
370 : }
371 :
372 5022 : len = 0;
373 :
374 26875 : for (i=0; i<attribs->num_eas; i++) {
375 21853 : strlcpy(list+len, attribs->eas[i].name,
376 : size-len);
377 21853 : len += (strlen(attribs->eas[i].name) + 1);
378 : }
379 :
380 5022 : TALLOC_FREE(frame);
381 5022 : return len;
382 : }
383 :
384 : /*
385 : * Worker routine for removexattr and fremovexattr
386 : */
387 :
388 38 : int xattr_tdb_removeattr(struct db_context *db_ctx,
389 : const struct file_id *id, const char *name)
390 : {
391 : NTSTATUS status;
392 : struct db_record *rec;
393 : struct tdb_xattrs *attribs;
394 : uint32_t i;
395 : TDB_DATA value;
396 :
397 38 : rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
398 :
399 38 : if (rec == NULL) {
400 0 : DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
401 0 : errno = EINVAL;
402 0 : return -1;
403 : }
404 :
405 38 : value = dbwrap_record_get_value(rec);
406 :
407 38 : status = xattr_tdb_pull_attrs(rec, &value, &attribs);
408 :
409 38 : 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 91 : for (i=0; i<attribs->num_eas; i++) {
417 61 : if (strcmp(attribs->eas[i].name, name) == 0) {
418 8 : break;
419 : }
420 : }
421 :
422 38 : if (i == attribs->num_eas) {
423 30 : TALLOC_FREE(rec);
424 30 : errno = ENOATTR;
425 30 : return -1;
426 : }
427 :
428 8 : attribs->eas[i] =
429 8 : attribs->eas[attribs->num_eas-1];
430 8 : attribs->num_eas -= 1;
431 :
432 8 : if (attribs->num_eas == 0) {
433 0 : dbwrap_record_delete(rec);
434 0 : TALLOC_FREE(rec);
435 0 : return 0;
436 : }
437 :
438 8 : status = xattr_tdb_save_attrs(rec, attribs);
439 :
440 8 : TALLOC_FREE(rec);
441 :
442 8 : if (!NT_STATUS_IS_OK(status)) {
443 0 : DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
444 0 : return -1;
445 : }
446 :
447 8 : return 0;
448 : }
449 :
450 : /*
451 : * Worker routine for unlink and rmdir
452 : */
453 :
454 3148 : void xattr_tdb_remove_all_attrs(struct db_context *db_ctx,
455 : const struct file_id *id)
456 : {
457 : struct db_record *rec;
458 3148 : 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 3148 : if (rec != NULL) {
465 3148 : dbwrap_record_delete(rec);
466 3148 : TALLOC_FREE(rec);
467 : }
468 3148 : }
|