s4-torture: Test for #9058
[Samba/gebeck_regimport.git] / source4 / ntvfs / posix / pvfs_xattr.c
blobab88d89d10bddab2ffcd244b80aca0518079c20c
1 /*
2 Unix SMB/CIFS implementation.
4 POSIX NTVFS backend - xattr support
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "vfs_posix.h"
24 #include "../lib/util/unix_privs.h"
25 #include "librpc/gen_ndr/ndr_xattr.h"
26 #include "param/param.h"
27 #include "ntvfs/posix/posix_eadb_proto.h"
30 pull a xattr as a blob
32 static NTSTATUS pull_xattr_blob(struct pvfs_state *pvfs,
33 TALLOC_CTX *mem_ctx,
34 const char *attr_name,
35 const char *fname,
36 int fd,
37 size_t estimated_size,
38 DATA_BLOB *blob)
40 NTSTATUS status;
42 if (pvfs->ea_db) {
43 return pull_xattr_blob_tdb(pvfs, mem_ctx, attr_name, fname,
44 fd, estimated_size, blob);
47 status = pull_xattr_blob_system(pvfs, mem_ctx, attr_name, fname,
48 fd, estimated_size, blob);
50 /* if the filesystem doesn't support them, then tell pvfs not to try again */
51 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)||
52 NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)||
53 NT_STATUS_EQUAL(status, NT_STATUS_INVALID_SYSTEM_SERVICE)) {
54 DEBUG(2,("pvfs_xattr: xattr not supported in filesystem: %s\n", nt_errstr(status)));
55 pvfs->flags &= ~PVFS_FLAG_XATTR_ENABLE;
56 status = NT_STATUS_NOT_FOUND;
59 return status;
63 push a xattr as a blob
65 static NTSTATUS push_xattr_blob(struct pvfs_state *pvfs,
66 const char *attr_name,
67 const char *fname,
68 int fd,
69 const DATA_BLOB *blob)
71 if (pvfs->ea_db) {
72 return push_xattr_blob_tdb(pvfs, attr_name, fname, fd, blob);
74 return push_xattr_blob_system(pvfs, attr_name, fname, fd, blob);
79 delete a xattr
81 static NTSTATUS delete_xattr(struct pvfs_state *pvfs, const char *attr_name,
82 const char *fname, int fd)
84 if (pvfs->ea_db) {
85 return delete_posix_eadb(pvfs, attr_name, fname, fd);
87 return delete_xattr_system(pvfs, attr_name, fname, fd);
91 a hook called on unlink - allows the tdb xattr backend to cleanup
93 NTSTATUS pvfs_xattr_unlink_hook(struct pvfs_state *pvfs, const char *fname)
95 if (pvfs->ea_db) {
96 return unlink_posix_eadb(pvfs, fname);
98 return unlink_xattr_system(pvfs, fname);
103 load a NDR structure from a xattr
105 NTSTATUS pvfs_xattr_ndr_load(struct pvfs_state *pvfs,
106 TALLOC_CTX *mem_ctx,
107 const char *fname, int fd, const char *attr_name,
108 void *p, void *pull_fn)
110 NTSTATUS status;
111 DATA_BLOB blob;
112 enum ndr_err_code ndr_err;
114 status = pull_xattr_blob(pvfs, mem_ctx, attr_name, fname,
115 fd, XATTR_DOSATTRIB_ESTIMATED_SIZE, &blob);
116 if (!NT_STATUS_IS_OK(status)) {
117 return status;
120 /* pull the blob */
121 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, p,
122 (ndr_pull_flags_fn_t)pull_fn);
123 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
124 return ndr_map_error2ntstatus(ndr_err);
127 data_blob_free(&blob);
129 return NT_STATUS_OK;
133 save a NDR structure into a xattr
135 NTSTATUS pvfs_xattr_ndr_save(struct pvfs_state *pvfs,
136 const char *fname, int fd, const char *attr_name,
137 void *p, void *push_fn)
139 TALLOC_CTX *mem_ctx = talloc_new(NULL);
140 DATA_BLOB blob;
141 NTSTATUS status;
142 enum ndr_err_code ndr_err;
144 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, p, (ndr_push_flags_fn_t)push_fn);
145 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
146 talloc_free(mem_ctx);
147 return ndr_map_error2ntstatus(ndr_err);
150 status = push_xattr_blob(pvfs, attr_name, fname, fd, &blob);
151 talloc_free(mem_ctx);
153 return status;
158 fill in file attributes from extended attributes
160 NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
162 NTSTATUS status;
163 struct xattr_DosAttrib attrib;
164 TALLOC_CTX *mem_ctx = talloc_new(name);
165 struct xattr_DosInfo1 *info1;
166 struct xattr_DosInfo2Old *info2;
168 if (name->stream_name != NULL) {
169 name->stream_exists = false;
170 } else {
171 name->stream_exists = true;
174 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
175 return NT_STATUS_OK;
178 status = pvfs_xattr_ndr_load(pvfs, mem_ctx, name->full_name,
179 fd, XATTR_DOSATTRIB_NAME,
180 &attrib,
181 (void *) ndr_pull_xattr_DosAttrib);
183 /* not having a DosAttrib is not an error */
184 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
185 talloc_free(mem_ctx);
186 return pvfs_stream_info(pvfs, name, fd);
189 if (!NT_STATUS_IS_OK(status)) {
190 talloc_free(mem_ctx);
191 return status;
194 switch (attrib.version) {
195 case 1:
196 info1 = &attrib.info.info1;
197 name->dos.attrib = pvfs_attrib_normalise(info1->attrib,
198 name->st.st_mode);
199 name->dos.ea_size = info1->ea_size;
200 if (name->st.st_size == info1->size) {
201 name->dos.alloc_size =
202 pvfs_round_alloc_size(pvfs, info1->alloc_size);
204 if (!null_nttime(info1->create_time)) {
205 name->dos.create_time = info1->create_time;
207 if (!null_nttime(info1->change_time)) {
208 name->dos.change_time = info1->change_time;
210 name->dos.flags = 0;
211 break;
213 case 2:
215 * Note: This is only used to parse existing values from disk
216 * We use xattr_DosInfo1 again for storing new values
218 info2 = &attrib.info.oldinfo2;
219 name->dos.attrib = pvfs_attrib_normalise(info2->attrib,
220 name->st.st_mode);
221 name->dos.ea_size = info2->ea_size;
222 if (name->st.st_size == info2->size) {
223 name->dos.alloc_size =
224 pvfs_round_alloc_size(pvfs, info2->alloc_size);
226 if (!null_nttime(info2->create_time)) {
227 name->dos.create_time = info2->create_time;
229 if (!null_nttime(info2->change_time)) {
230 name->dos.change_time = info2->change_time;
232 name->dos.flags = info2->flags;
233 break;
235 default:
236 DEBUG(0,("ERROR: Unsupported xattr DosAttrib version %d on '%s'\n",
237 attrib.version, name->full_name));
238 talloc_free(mem_ctx);
239 return NT_STATUS_INVALID_LEVEL;
241 talloc_free(mem_ctx);
243 status = pvfs_stream_info(pvfs, name, fd);
245 return status;
250 save the file attribute into the xattr
252 NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
254 struct xattr_DosAttrib attrib;
255 struct xattr_DosInfo1 *info1;
257 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
258 return NT_STATUS_OK;
261 attrib.version = 1;
262 info1 = &attrib.info.info1;
264 name->dos.attrib = pvfs_attrib_normalise(name->dos.attrib, name->st.st_mode);
266 info1->attrib = name->dos.attrib;
267 info1->ea_size = name->dos.ea_size;
268 info1->size = name->st.st_size;
269 info1->alloc_size = name->dos.alloc_size;
270 info1->create_time = name->dos.create_time;
271 info1->change_time = name->dos.change_time;
273 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
274 XATTR_DOSATTRIB_NAME, &attrib,
275 (void *) ndr_push_xattr_DosAttrib);
280 load the set of DOS EAs
282 NTSTATUS pvfs_doseas_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
283 struct xattr_DosEAs *eas)
285 NTSTATUS status;
286 ZERO_STRUCTP(eas);
288 if (name->stream_name) {
289 /* We don't support EAs on streams */
290 return NT_STATUS_INVALID_PARAMETER;
293 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
294 return NT_STATUS_OK;
296 status = pvfs_xattr_ndr_load(pvfs, eas, name->full_name, fd, XATTR_DOSEAS_NAME,
297 eas, (void *) ndr_pull_xattr_DosEAs);
298 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
299 return NT_STATUS_OK;
301 return status;
305 save the set of DOS EAs
307 NTSTATUS pvfs_doseas_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
308 struct xattr_DosEAs *eas)
310 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
311 return NT_STATUS_OK;
313 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, XATTR_DOSEAS_NAME, eas,
314 (void *) ndr_push_xattr_DosEAs);
319 load the set of streams from extended attributes
321 NTSTATUS pvfs_streams_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
322 struct xattr_DosStreams *streams)
324 NTSTATUS status;
325 ZERO_STRUCTP(streams);
326 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
327 return NT_STATUS_OK;
329 status = pvfs_xattr_ndr_load(pvfs, streams, name->full_name, fd,
330 XATTR_DOSSTREAMS_NAME,
331 streams,
332 (void *) ndr_pull_xattr_DosStreams);
333 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
334 return NT_STATUS_OK;
336 return status;
340 save the set of streams into filesystem xattr
342 NTSTATUS pvfs_streams_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
343 struct xattr_DosStreams *streams)
345 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
346 return NT_STATUS_OK;
348 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
349 XATTR_DOSSTREAMS_NAME,
350 streams,
351 (void *) ndr_push_xattr_DosStreams);
356 load the current ACL from extended attributes
358 NTSTATUS pvfs_acl_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
359 struct xattr_NTACL *acl)
361 NTSTATUS status;
362 ZERO_STRUCTP(acl);
363 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
364 return NT_STATUS_NOT_FOUND;
366 status = pvfs_xattr_ndr_load(pvfs, acl, name->full_name, fd,
367 XATTR_NTACL_NAME,
368 acl,
369 (void *) ndr_pull_xattr_NTACL);
370 return status;
374 save the acl for a file into filesystem xattr
376 NTSTATUS pvfs_acl_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
377 struct xattr_NTACL *acl)
379 NTSTATUS status;
380 void *privs;
382 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
383 return NT_STATUS_OK;
386 /* this xattr is in the "system" namespace, so we need
387 admin privileges to set it */
388 privs = root_privileges();
389 status = pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
390 XATTR_NTACL_NAME,
391 acl,
392 (void *) ndr_push_xattr_NTACL);
393 talloc_free(privs);
394 return status;
398 create a zero length xattr with the given name
400 NTSTATUS pvfs_xattr_create(struct pvfs_state *pvfs,
401 const char *fname, int fd,
402 const char *attr_prefix,
403 const char *attr_name)
405 NTSTATUS status;
406 DATA_BLOB blob = data_blob(NULL, 0);
407 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
408 if (aname == NULL) {
409 return NT_STATUS_NO_MEMORY;
411 status = push_xattr_blob(pvfs, aname, fname, fd, &blob);
412 talloc_free(aname);
413 return status;
418 delete a xattr with the given name
420 NTSTATUS pvfs_xattr_delete(struct pvfs_state *pvfs,
421 const char *fname, int fd,
422 const char *attr_prefix,
423 const char *attr_name)
425 NTSTATUS status;
426 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
427 if (aname == NULL) {
428 return NT_STATUS_NO_MEMORY;
430 status = delete_xattr(pvfs, aname, fname, fd);
431 talloc_free(aname);
432 return status;
436 load a xattr with the given name
438 NTSTATUS pvfs_xattr_load(struct pvfs_state *pvfs,
439 TALLOC_CTX *mem_ctx,
440 const char *fname, int fd,
441 const char *attr_prefix,
442 const char *attr_name,
443 size_t estimated_size,
444 DATA_BLOB *blob)
446 NTSTATUS status;
447 char *aname = talloc_asprintf(mem_ctx, "%s%s", attr_prefix, attr_name);
448 if (aname == NULL) {
449 return NT_STATUS_NO_MEMORY;
451 status = pull_xattr_blob(pvfs, mem_ctx, aname, fname, fd, estimated_size, blob);
452 talloc_free(aname);
453 return status;
457 save a xattr with the given name
459 NTSTATUS pvfs_xattr_save(struct pvfs_state *pvfs,
460 const char *fname, int fd,
461 const char *attr_prefix,
462 const char *attr_name,
463 const DATA_BLOB *blob)
465 NTSTATUS status;
466 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
467 if (aname == NULL) {
468 return NT_STATUS_NO_MEMORY;
470 status = push_xattr_blob(pvfs, aname, fname, fd, blob);
471 talloc_free(aname);
472 return status;
477 probe for system support for xattrs
479 void pvfs_xattr_probe(struct pvfs_state *pvfs)
481 TALLOC_CTX *tmp_ctx = talloc_new(pvfs);
482 DATA_BLOB blob;
483 pull_xattr_blob(pvfs, tmp_ctx, "user.XattrProbe", pvfs->base_directory,
484 -1, 1, &blob);
485 pull_xattr_blob(pvfs, tmp_ctx, "security.XattrProbe", pvfs->base_directory,
486 -1, 1, &blob);
487 talloc_free(tmp_ctx);