pyldb: avoid segfault when adding an element with no name
[kamenim/samba-autobuild/.git] / source3 / lib / xattr_tdb.c
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 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         if (!(result = talloc_zero(mem_ctx, struct tdb_xattrs))) {
50                 return NT_STATUS_NO_MEMORY;
51         }
52
53         if (data->dsize == 0) {
54                 *presult = result;
55                 return NT_STATUS_OK;
56         }
57
58         blob = data_blob_const(data->dptr, data->dsize);
59
60         ndr_err = ndr_pull_struct_blob(&blob, result, result,
61                 (ndr_pull_flags_fn_t)ndr_pull_tdb_xattrs);
62
63         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
64                 DEBUG(0, ("ndr_pull_tdb_xattrs failed: %s\n",
65                           ndr_errstr(ndr_err)));
66                 TALLOC_FREE(result);
67                 return ndr_map_error2ntstatus(ndr_err);
68         }
69
70         *presult = result;
71         return NT_STATUS_OK;
72 }
73
74 /*
75  * marshall tdb_xattrs
76  */
77
78 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         ndr_err = ndr_push_struct_blob(&blob, mem_ctx, attribs,
86                 (ndr_push_flags_fn_t)ndr_push_tdb_xattrs);
87
88         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
89                 DEBUG(0, ("ndr_push_tdb_xattrs failed: %s\n",
90                           ndr_errstr(ndr_err)));
91                 return ndr_map_error2ntstatus(ndr_err);
92         }
93
94         *data = make_tdb_data(blob.data, blob.length);
95         return NT_STATUS_OK;
96 }
97
98 /*
99  * Load tdb_xattrs for a file from the tdb
100  */
101
102 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         push_file_id_16((char *)id_buf, id);
113
114         status = dbwrap_fetch(db_ctx, mem_ctx,
115                               make_tdb_data(id_buf, sizeof(id_buf)),
116                               &data);
117         if (!NT_STATUS_IS_OK(status)) {
118                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
119                         return status;
120                 }
121                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
122         }
123
124         status = xattr_tdb_pull_attrs(mem_ctx, &data, presult);
125         TALLOC_FREE(data.dptr);
126         return status;
127 }
128
129 /*
130  * fetch_lock the tdb_ea record for a file
131  */
132
133 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         push_file_id_16((char *)id_buf, id);
141         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 static NTSTATUS xattr_tdb_save_attrs(struct db_record *rec,
150                                      const struct tdb_xattrs *attribs)
151 {
152         TDB_DATA data = tdb_null;
153         NTSTATUS status;
154
155         status = xattr_tdb_push_attrs(talloc_tos(), attribs, &data);
156
157         if (!NT_STATUS_IS_OK(status)) {
158                 DEBUG(0, ("xattr_tdb_push_attrs failed: %s\n",
159                           nt_errstr(status)));
160                 return status;
161         }
162
163         status = dbwrap_record_store(rec, data, 0);
164
165         TALLOC_FREE(data.dptr);
166
167         return status;
168 }
169
170 /*
171  * Worker routine for getxattr and fgetxattr
172  */
173
174 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         ssize_t result = -1;
182         NTSTATUS status;
183         TALLOC_CTX *frame = talloc_stackframe();
184
185         DEBUG(10, ("xattr_tdb_getattr called for file %s, name %s\n",
186                    file_id_string(frame, id), name));
187
188         status = xattr_tdb_load_attrs(frame, db_ctx, id, &attribs);
189
190         if (!NT_STATUS_IS_OK(status)) {
191                 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
192                            nt_errstr(status)));
193                 TALLOC_FREE(frame);
194                 errno = EINVAL;
195                 return -1;
196         }
197
198         for (i=0; i<attribs->num_eas; i++) {
199                 if (strcmp(attribs->eas[i].name, name) == 0) {
200                         break;
201                 }
202         }
203
204         if (i == attribs->num_eas) {
205                 errno = ENOATTR;
206                 goto fail;
207         }
208
209         *blob = attribs->eas[i].value;
210         talloc_steal(mem_ctx, blob->data);
211         result = attribs->eas[i].value.length;
212
213  fail:
214         TALLOC_FREE(frame);
215         return result;
216 }
217
218 /*
219  * Worker routine for setxattr and fsetxattr
220  */
221
222 int xattr_tdb_setattr(struct db_context *db_ctx,
223                       const struct file_id *id, const char *name,
224                       const void *value, size_t size, int flags)
225 {
226         NTSTATUS status;
227         struct db_record *rec;
228         struct tdb_xattrs *attribs;
229         uint32_t i;
230         TDB_DATA data;
231         TALLOC_CTX *frame = talloc_stackframe();
232
233         DEBUG(10, ("xattr_tdb_setattr called for file %s, name %s\n",
234                    file_id_string(frame, id), name));
235
236         rec = xattr_tdb_lock_attrs(frame, db_ctx, id);
237
238         if (rec == NULL) {
239                 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
240                 errno = EINVAL;
241                 return -1;
242         }
243
244         data = dbwrap_record_get_value(rec);
245
246         status = xattr_tdb_pull_attrs(rec, &data, &attribs);
247
248         if (!NT_STATUS_IS_OK(status)) {
249                 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
250                            nt_errstr(status)));
251                 TALLOC_FREE(frame);
252                 return -1;
253         }
254
255         for (i=0; i<attribs->num_eas; i++) {
256                 if (strcmp(attribs->eas[i].name, name) == 0) {
257                         if (flags & XATTR_CREATE) {
258                                 TALLOC_FREE(frame);
259                                 errno = EEXIST;
260                                 return -1;
261                         }
262                         break;
263                 }
264         }
265
266         if (i == attribs->num_eas) {
267                 struct xattr_EA *tmp;
268
269                 if (flags & XATTR_REPLACE) {
270                         TALLOC_FREE(frame);
271                         errno = ENOATTR;
272                         return -1;
273                 }
274
275                 tmp = talloc_realloc(
276                         attribs, attribs->eas, struct xattr_EA,
277                         attribs->num_eas+ 1);
278
279                 if (tmp == NULL) {
280                         DEBUG(0, ("talloc_realloc failed\n"));
281                         TALLOC_FREE(frame);
282                         errno = ENOMEM;
283                         return -1;
284                 }
285
286                 attribs->eas = tmp;
287                 attribs->num_eas += 1;
288         }
289
290         attribs->eas[i].name = name;
291         attribs->eas[i].value.data = discard_const_p(uint8_t, value);
292         attribs->eas[i].value.length = size;
293
294         status = xattr_tdb_save_attrs(rec, attribs);
295
296         TALLOC_FREE(frame);
297
298         if (!NT_STATUS_IS_OK(status)) {
299                 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
300                 return -1;
301         }
302
303         return 0;
304 }
305
306 /*
307  * Worker routine for listxattr and flistxattr
308  */
309
310 ssize_t xattr_tdb_listattr(struct db_context *db_ctx,
311                            const struct file_id *id, char *list,
312                            size_t size)
313 {
314         NTSTATUS status;
315         struct tdb_xattrs *attribs;
316         uint32_t i;
317         size_t len = 0;
318         TALLOC_CTX *frame = talloc_stackframe();
319
320         status = xattr_tdb_load_attrs(frame, db_ctx, id, &attribs);
321
322         if (!NT_STATUS_IS_OK(status) &&
323             !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND))
324         {
325                 DEBUG(0, ("xattr_tdb_fetch_attrs failed: %s\n",
326                            nt_errstr(status)));
327                 errno = EINVAL;
328                 TALLOC_FREE(frame);
329                 return -1;
330         }
331
332         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
333                 TALLOC_FREE(frame);
334                 return 0;
335         }
336
337         DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n",
338                    attribs->num_eas));
339
340         for (i=0; i<attribs->num_eas; i++) {
341                 size_t tmp;
342
343                 DEBUG(10, ("xattr_tdb_listattr: xattrs[i].name: %s\n",
344                            attribs->eas[i].name));
345
346                 tmp = strlen(attribs->eas[i].name);
347
348                 /*
349                  * Try to protect against overflow
350                  */
351
352                 if (len + (tmp+1) < len) {
353                         TALLOC_FREE(frame);
354                         errno = EINVAL;
355                         return -1;
356                 }
357
358                 /*
359                  * Take care of the terminating NULL
360                  */
361                 len += (tmp + 1);
362         }
363
364         if (len > size) {
365                 TALLOC_FREE(frame);
366                 errno = ERANGE;
367                 return len;
368         }
369
370         len = 0;
371
372         for (i=0; i<attribs->num_eas; i++) {
373                 strlcpy(list+len, attribs->eas[i].name,
374                         size-len);
375                 len += (strlen(attribs->eas[i].name) + 1);
376         }
377
378         TALLOC_FREE(frame);
379         return len;
380 }
381
382 /*
383  * Worker routine for removexattr and fremovexattr
384  */
385
386 int xattr_tdb_removeattr(struct db_context *db_ctx,
387                          const struct file_id *id, const char *name)
388 {
389         NTSTATUS status;
390         struct db_record *rec;
391         struct tdb_xattrs *attribs;
392         uint32_t i;
393         TDB_DATA value;
394
395         rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
396
397         if (rec == NULL) {
398                 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
399                 errno = EINVAL;
400                 return -1;
401         }
402
403         value = dbwrap_record_get_value(rec);
404
405         status = xattr_tdb_pull_attrs(rec, &value, &attribs);
406
407         if (!NT_STATUS_IS_OK(status)) {
408                 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
409                            nt_errstr(status)));
410                 TALLOC_FREE(rec);
411                 return -1;
412         }
413
414         for (i=0; i<attribs->num_eas; i++) {
415                 if (strcmp(attribs->eas[i].name, name) == 0) {
416                         break;
417                 }
418         }
419
420         if (i == attribs->num_eas) {
421                 TALLOC_FREE(rec);
422                 errno = ENOATTR;
423                 return -1;
424         }
425
426         attribs->eas[i] =
427                 attribs->eas[attribs->num_eas-1];
428         attribs->num_eas -= 1;
429
430         if (attribs->num_eas == 0) {
431                 dbwrap_record_delete(rec);
432                 TALLOC_FREE(rec);
433                 return 0;
434         }
435
436         status = xattr_tdb_save_attrs(rec, attribs);
437
438         TALLOC_FREE(rec);
439
440         if (!NT_STATUS_IS_OK(status)) {
441                 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
442                 return -1;
443         }
444
445         return 0;
446 }
447
448 /*
449  * Worker routine for unlink and rmdir
450  */
451
452 void xattr_tdb_remove_all_attrs(struct db_context *db_ctx,
453                                const struct file_id *id)
454 {
455         struct db_record *rec;
456         rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
457
458         /*
459          * If rec == NULL there's not much we can do about it
460          */
461
462         if (rec != NULL) {
463                 dbwrap_record_delete(rec);
464                 TALLOC_FREE(rec);
465         }
466 }