Decouple ldap-ssl-ads from ldap-ssl option
[samba.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         struct file_id_buf buf;
185
186         DBG_DEBUG("xattr_tdb_getattr called for file %s, name %s\n",
187                   file_id_str_buf(*id, &buf), name);
188
189         status = xattr_tdb_load_attrs(frame, db_ctx, id, &attribs);
190
191         if (!NT_STATUS_IS_OK(status)) {
192                 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
193                            nt_errstr(status)));
194                 TALLOC_FREE(frame);
195                 errno = EINVAL;
196                 return -1;
197         }
198
199         for (i=0; i<attribs->num_eas; i++) {
200                 if (strcmp(attribs->eas[i].name, name) == 0) {
201                         break;
202                 }
203         }
204
205         if (i == attribs->num_eas) {
206                 errno = ENOATTR;
207                 goto fail;
208         }
209
210         *blob = attribs->eas[i].value;
211         talloc_steal(mem_ctx, blob->data);
212         result = attribs->eas[i].value.length;
213
214  fail:
215         TALLOC_FREE(frame);
216         return result;
217 }
218
219 /*
220  * Worker routine for setxattr and fsetxattr
221  */
222
223 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         TALLOC_CTX *frame = talloc_stackframe();
233         struct file_id_buf buf;
234
235         DBG_DEBUG("xattr_tdb_setattr called for file %s, name %s\n",
236                   file_id_str_buf(*id, &buf), name);
237
238         rec = xattr_tdb_lock_attrs(frame, db_ctx, id);
239
240         if (rec == NULL) {
241                 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
242                 errno = EINVAL;
243                 return -1;
244         }
245
246         data = dbwrap_record_get_value(rec);
247
248         status = xattr_tdb_pull_attrs(rec, &data, &attribs);
249
250         if (!NT_STATUS_IS_OK(status)) {
251                 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
252                            nt_errstr(status)));
253                 TALLOC_FREE(frame);
254                 return -1;
255         }
256
257         for (i=0; i<attribs->num_eas; i++) {
258                 if (strcmp(attribs->eas[i].name, name) == 0) {
259                         if (flags & XATTR_CREATE) {
260                                 TALLOC_FREE(frame);
261                                 errno = EEXIST;
262                                 return -1;
263                         }
264                         break;
265                 }
266         }
267
268         if (i == attribs->num_eas) {
269                 struct xattr_EA *tmp;
270
271                 if (flags & XATTR_REPLACE) {
272                         TALLOC_FREE(frame);
273                         errno = ENOATTR;
274                         return -1;
275                 }
276
277                 tmp = talloc_realloc(
278                         attribs, attribs->eas, struct xattr_EA,
279                         attribs->num_eas+ 1);
280
281                 if (tmp == NULL) {
282                         DEBUG(0, ("talloc_realloc failed\n"));
283                         TALLOC_FREE(frame);
284                         errno = ENOMEM;
285                         return -1;
286                 }
287
288                 attribs->eas = tmp;
289                 attribs->num_eas += 1;
290         }
291
292         attribs->eas[i].name = name;
293         attribs->eas[i].value.data = discard_const_p(uint8_t, value);
294         attribs->eas[i].value.length = size;
295
296         status = xattr_tdb_save_attrs(rec, attribs);
297
298         TALLOC_FREE(frame);
299
300         if (!NT_STATUS_IS_OK(status)) {
301                 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
302                 return -1;
303         }
304
305         return 0;
306 }
307
308 /*
309  * Worker routine for listxattr and flistxattr
310  */
311
312 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         size_t len = 0;
320         TALLOC_CTX *frame = talloc_stackframe();
321
322         status = xattr_tdb_load_attrs(frame, db_ctx, id, &attribs);
323
324         if (!NT_STATUS_IS_OK(status) &&
325             !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND))
326         {
327                 DEBUG(0, ("xattr_tdb_fetch_attrs failed: %s\n",
328                            nt_errstr(status)));
329                 errno = EINVAL;
330                 TALLOC_FREE(frame);
331                 return -1;
332         }
333
334         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
335                 TALLOC_FREE(frame);
336                 return 0;
337         }
338
339         DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n",
340                    attribs->num_eas));
341
342         for (i=0; i<attribs->num_eas; i++) {
343                 size_t tmp;
344
345                 DEBUG(10, ("xattr_tdb_listattr: xattrs[i].name: %s\n",
346                            attribs->eas[i].name));
347
348                 tmp = strlen(attribs->eas[i].name);
349
350                 /*
351                  * Try to protect against overflow
352                  */
353
354                 if (len + (tmp+1) < len) {
355                         TALLOC_FREE(frame);
356                         errno = EINVAL;
357                         return -1;
358                 }
359
360                 /*
361                  * Take care of the terminating NULL
362                  */
363                 len += (tmp + 1);
364         }
365
366         if (len > size) {
367                 TALLOC_FREE(frame);
368                 errno = ERANGE;
369                 return len;
370         }
371
372         len = 0;
373
374         for (i=0; i<attribs->num_eas; i++) {
375                 strlcpy(list+len, attribs->eas[i].name,
376                         size-len);
377                 len += (strlen(attribs->eas[i].name) + 1);
378         }
379
380         TALLOC_FREE(frame);
381         return len;
382 }
383
384 /*
385  * Worker routine for removexattr and fremovexattr
386  */
387
388 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         rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
398
399         if (rec == NULL) {
400                 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
401                 errno = EINVAL;
402                 return -1;
403         }
404
405         value = dbwrap_record_get_value(rec);
406
407         status = xattr_tdb_pull_attrs(rec, &value, &attribs);
408
409         if (!NT_STATUS_IS_OK(status)) {
410                 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
411                            nt_errstr(status)));
412                 TALLOC_FREE(rec);
413                 return -1;
414         }
415
416         for (i=0; i<attribs->num_eas; i++) {
417                 if (strcmp(attribs->eas[i].name, name) == 0) {
418                         break;
419                 }
420         }
421
422         if (i == attribs->num_eas) {
423                 TALLOC_FREE(rec);
424                 errno = ENOATTR;
425                 return -1;
426         }
427
428         attribs->eas[i] =
429                 attribs->eas[attribs->num_eas-1];
430         attribs->num_eas -= 1;
431
432         if (attribs->num_eas == 0) {
433                 dbwrap_record_delete(rec);
434                 TALLOC_FREE(rec);
435                 return 0;
436         }
437
438         status = xattr_tdb_save_attrs(rec, attribs);
439
440         TALLOC_FREE(rec);
441
442         if (!NT_STATUS_IS_OK(status)) {
443                 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
444                 return -1;
445         }
446
447         return 0;
448 }
449
450 /*
451  * Worker routine for unlink and rmdir
452  */
453
454 void xattr_tdb_remove_all_attrs(struct db_context *db_ctx,
455                                const struct file_id *id)
456 {
457         struct db_record *rec;
458         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         if (rec != NULL) {
465                 dbwrap_record_delete(rec);
466                 TALLOC_FREE(rec);
467         }
468 }