• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/samba-3.5.8/source4/ntvfs/posix/
1/*
2   Unix SMB/CIFS implementation.
3
4   POSIX NTVFS backend - xattr support
5
6   Copyright (C) Andrew Tridgell 2004
7
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.
12
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.
17
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/>.
20*/
21
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
28/*
29  pull a xattr as a blob
30*/
31static NTSTATUS pull_xattr_blob(struct pvfs_state *pvfs,
32				TALLOC_CTX *mem_ctx,
33				const char *attr_name,
34				const char *fname,
35				int fd,
36				size_t estimated_size,
37				DATA_BLOB *blob)
38{
39	NTSTATUS status;
40
41	if (pvfs->ea_db) {
42		return pull_xattr_blob_tdb(pvfs, mem_ctx, attr_name, fname,
43					   fd, estimated_size, blob);
44	}
45
46	status = pull_xattr_blob_system(pvfs, mem_ctx, attr_name, fname,
47					fd, estimated_size, blob);
48
49	/* if the filesystem doesn't support them, then tell pvfs not to try again */
50	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)||
51	    NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)||
52	    NT_STATUS_EQUAL(status, NT_STATUS_INVALID_SYSTEM_SERVICE)) {
53		DEBUG(2,("pvfs_xattr: xattr not supported in filesystem: %s\n", nt_errstr(status)));
54		pvfs->flags &= ~PVFS_FLAG_XATTR_ENABLE;
55		status = NT_STATUS_NOT_FOUND;
56	}
57
58	return status;
59}
60
61/*
62  push a xattr as a blob
63*/
64static NTSTATUS push_xattr_blob(struct pvfs_state *pvfs,
65				const char *attr_name,
66				const char *fname,
67				int fd,
68				const DATA_BLOB *blob)
69{
70	if (pvfs->ea_db) {
71		return push_xattr_blob_tdb(pvfs, attr_name, fname, fd, blob);
72	}
73	return push_xattr_blob_system(pvfs, attr_name, fname, fd, blob);
74}
75
76
77/*
78  delete a xattr
79*/
80static NTSTATUS delete_xattr(struct pvfs_state *pvfs, const char *attr_name,
81			     const char *fname, int fd)
82{
83	if (pvfs->ea_db) {
84		return delete_xattr_tdb(pvfs, attr_name, fname, fd);
85	}
86	return delete_xattr_system(pvfs, attr_name, fname, fd);
87}
88
89/*
90  a hook called on unlink - allows the tdb xattr backend to cleanup
91*/
92NTSTATUS pvfs_xattr_unlink_hook(struct pvfs_state *pvfs, const char *fname)
93{
94	if (pvfs->ea_db) {
95		return unlink_xattr_tdb(pvfs, fname);
96	}
97	return unlink_xattr_system(pvfs, fname);
98}
99
100
101/*
102  load a NDR structure from a xattr
103*/
104NTSTATUS pvfs_xattr_ndr_load(struct pvfs_state *pvfs,
105			     TALLOC_CTX *mem_ctx,
106			     const char *fname, int fd, const char *attr_name,
107			     void *p, void *pull_fn)
108{
109	NTSTATUS status;
110	DATA_BLOB blob;
111	enum ndr_err_code ndr_err;
112
113	status = pull_xattr_blob(pvfs, mem_ctx, attr_name, fname,
114				 fd, XATTR_DOSATTRIB_ESTIMATED_SIZE, &blob);
115	if (!NT_STATUS_IS_OK(status)) {
116		return status;
117	}
118
119	/* pull the blob */
120	ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, lp_iconv_convenience(pvfs->ntvfs->ctx->lp_ctx),
121				       p, (ndr_pull_flags_fn_t)pull_fn);
122	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
123		return ndr_map_error2ntstatus(ndr_err);
124	}
125
126	data_blob_free(&blob);
127
128	return NT_STATUS_OK;
129}
130
131/*
132  save a NDR structure into a xattr
133*/
134NTSTATUS pvfs_xattr_ndr_save(struct pvfs_state *pvfs,
135			     const char *fname, int fd, const char *attr_name,
136			     void *p, void *push_fn)
137{
138	TALLOC_CTX *mem_ctx = talloc_new(NULL);
139	DATA_BLOB blob;
140	NTSTATUS status;
141	enum ndr_err_code ndr_err;
142
143	ndr_err = ndr_push_struct_blob(&blob, mem_ctx, lp_iconv_convenience(pvfs->ntvfs->ctx->lp_ctx), p, (ndr_push_flags_fn_t)push_fn);
144	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
145		talloc_free(mem_ctx);
146		return ndr_map_error2ntstatus(ndr_err);
147	}
148
149	status = push_xattr_blob(pvfs, attr_name, fname, fd, &blob);
150	talloc_free(mem_ctx);
151
152	return status;
153}
154
155
156/*
157  fill in file attributes from extended attributes
158*/
159NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
160{
161	NTSTATUS status;
162	struct xattr_DosAttrib attrib;
163	TALLOC_CTX *mem_ctx = talloc_new(name);
164	struct xattr_DosInfo1 *info1;
165	struct xattr_DosInfo2Old *info2;
166
167	if (name->stream_name != NULL) {
168		name->stream_exists = false;
169	} else {
170		name->stream_exists = true;
171	}
172
173	if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
174		return NT_STATUS_OK;
175	}
176
177	status = pvfs_xattr_ndr_load(pvfs, mem_ctx, name->full_name,
178				     fd, XATTR_DOSATTRIB_NAME,
179				     &attrib,
180				     (ndr_pull_flags_fn_t)ndr_pull_xattr_DosAttrib);
181
182	/* not having a DosAttrib is not an error */
183	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
184		talloc_free(mem_ctx);
185		return pvfs_stream_info(pvfs, name, fd);
186	}
187
188	if (!NT_STATUS_IS_OK(status)) {
189		talloc_free(mem_ctx);
190		return status;
191	}
192
193	switch (attrib.version) {
194	case 1:
195		info1 = &attrib.info.info1;
196		name->dos.attrib = pvfs_attrib_normalise(info1->attrib,
197							 name->st.st_mode);
198		name->dos.ea_size = info1->ea_size;
199		if (name->st.st_size == info1->size) {
200			name->dos.alloc_size =
201				pvfs_round_alloc_size(pvfs, info1->alloc_size);
202		}
203		if (!null_nttime(info1->create_time)) {
204			name->dos.create_time = info1->create_time;
205		}
206		if (!null_nttime(info1->change_time)) {
207			name->dos.change_time = info1->change_time;
208		}
209		name->dos.flags = 0;
210		break;
211
212	case 2:
213		/*
214		 * Note: This is only used to parse existing values from disk
215		 *       We use xattr_DosInfo1 again for storing new values
216		 */
217		info2 = &attrib.info.oldinfo2;
218		name->dos.attrib = pvfs_attrib_normalise(info2->attrib,
219							 name->st.st_mode);
220		name->dos.ea_size = info2->ea_size;
221		if (name->st.st_size == info2->size) {
222			name->dos.alloc_size =
223				pvfs_round_alloc_size(pvfs, info2->alloc_size);
224		}
225		if (!null_nttime(info2->create_time)) {
226			name->dos.create_time = info2->create_time;
227		}
228		if (!null_nttime(info2->change_time)) {
229			name->dos.change_time = info2->change_time;
230		}
231		name->dos.flags = info2->flags;
232		break;
233
234	default:
235		DEBUG(0,("ERROR: Unsupported xattr DosAttrib version %d on '%s'\n",
236			 attrib.version, name->full_name));
237		talloc_free(mem_ctx);
238		return NT_STATUS_INVALID_LEVEL;
239	}
240	talloc_free(mem_ctx);
241
242	status = pvfs_stream_info(pvfs, name, fd);
243
244	return status;
245}
246
247
248/*
249  save the file attribute into the xattr
250*/
251NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
252{
253	struct xattr_DosAttrib attrib;
254	struct xattr_DosInfo1 *info1;
255
256	if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
257		return NT_STATUS_OK;
258	}
259
260	attrib.version = 1;
261	info1 = &attrib.info.info1;
262
263	name->dos.attrib = pvfs_attrib_normalise(name->dos.attrib, name->st.st_mode);
264
265	info1->attrib      = name->dos.attrib;
266	info1->ea_size     = name->dos.ea_size;
267	info1->size        = name->st.st_size;
268	info1->alloc_size  = name->dos.alloc_size;
269	info1->create_time = name->dos.create_time;
270	info1->change_time = name->dos.change_time;
271
272	return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
273				   XATTR_DOSATTRIB_NAME, &attrib,
274				   (ndr_push_flags_fn_t)ndr_push_xattr_DosAttrib);
275}
276
277
278/*
279  load the set of DOS EAs
280*/
281NTSTATUS pvfs_doseas_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
282			  struct xattr_DosEAs *eas)
283{
284	NTSTATUS status;
285	ZERO_STRUCTP(eas);
286	if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
287		return NT_STATUS_OK;
288	}
289	status = pvfs_xattr_ndr_load(pvfs, eas, name->full_name, fd, XATTR_DOSEAS_NAME,
290				     eas, (ndr_pull_flags_fn_t)ndr_pull_xattr_DosEAs);
291	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
292		return NT_STATUS_OK;
293	}
294	return status;
295}
296
297/*
298  save the set of DOS EAs
299*/
300NTSTATUS pvfs_doseas_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
301			  struct xattr_DosEAs *eas)
302{
303	if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
304		return NT_STATUS_OK;
305	}
306	return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, XATTR_DOSEAS_NAME, eas,
307				   (ndr_push_flags_fn_t)ndr_push_xattr_DosEAs);
308}
309
310
311/*
312  load the set of streams from extended attributes
313*/
314NTSTATUS pvfs_streams_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
315			   struct xattr_DosStreams *streams)
316{
317	NTSTATUS status;
318	ZERO_STRUCTP(streams);
319	if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
320		return NT_STATUS_OK;
321	}
322	status = pvfs_xattr_ndr_load(pvfs, streams, name->full_name, fd,
323				     XATTR_DOSSTREAMS_NAME,
324				     streams,
325				     (ndr_pull_flags_fn_t)ndr_pull_xattr_DosStreams);
326	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
327		return NT_STATUS_OK;
328	}
329	return status;
330}
331
332/*
333  save the set of streams into filesystem xattr
334*/
335NTSTATUS pvfs_streams_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
336			   struct xattr_DosStreams *streams)
337{
338	if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
339		return NT_STATUS_OK;
340	}
341	return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
342				   XATTR_DOSSTREAMS_NAME,
343				   streams,
344				   (ndr_push_flags_fn_t)ndr_push_xattr_DosStreams);
345}
346
347
348/*
349  load the current ACL from extended attributes
350*/
351NTSTATUS pvfs_acl_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
352		       struct xattr_NTACL *acl)
353{
354	NTSTATUS status;
355	ZERO_STRUCTP(acl);
356	if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
357		return NT_STATUS_NOT_FOUND;
358	}
359	status = pvfs_xattr_ndr_load(pvfs, acl, name->full_name, fd,
360				     XATTR_NTACL_NAME,
361				     acl,
362				     (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
363	return status;
364}
365
366/*
367  save the acl for a file into filesystem xattr
368*/
369NTSTATUS pvfs_acl_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
370		       struct xattr_NTACL *acl)
371{
372	NTSTATUS status;
373	void *privs;
374
375	if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
376		return NT_STATUS_OK;
377	}
378
379	/* this xattr is in the "system" namespace, so we need
380	   admin privileges to set it */
381	privs = root_privileges();
382	status = pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
383				     XATTR_NTACL_NAME,
384				     acl,
385				     (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
386	talloc_free(privs);
387	return status;
388}
389
390/*
391  create a zero length xattr with the given name
392*/
393NTSTATUS pvfs_xattr_create(struct pvfs_state *pvfs,
394			   const char *fname, int fd,
395			   const char *attr_prefix,
396			   const char *attr_name)
397{
398	NTSTATUS status;
399	DATA_BLOB blob = data_blob(NULL, 0);
400	char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
401	if (aname == NULL) {
402		return NT_STATUS_NO_MEMORY;
403	}
404	status = push_xattr_blob(pvfs, aname, fname, fd, &blob);
405	talloc_free(aname);
406	return status;
407}
408
409
410/*
411  delete a xattr with the given name
412*/
413NTSTATUS pvfs_xattr_delete(struct pvfs_state *pvfs,
414			   const char *fname, int fd,
415			   const char *attr_prefix,
416			   const char *attr_name)
417{
418	NTSTATUS status;
419	char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
420	if (aname == NULL) {
421		return NT_STATUS_NO_MEMORY;
422	}
423	status = delete_xattr(pvfs, aname, fname, fd);
424	talloc_free(aname);
425	return status;
426}
427
428/*
429  load a xattr with the given name
430*/
431NTSTATUS pvfs_xattr_load(struct pvfs_state *pvfs,
432			 TALLOC_CTX *mem_ctx,
433			 const char *fname, int fd,
434			 const char *attr_prefix,
435			 const char *attr_name,
436			 size_t estimated_size,
437			 DATA_BLOB *blob)
438{
439	NTSTATUS status;
440	char *aname = talloc_asprintf(mem_ctx, "%s%s", attr_prefix, attr_name);
441	if (aname == NULL) {
442		return NT_STATUS_NO_MEMORY;
443	}
444	status = pull_xattr_blob(pvfs, mem_ctx, aname, fname, fd, estimated_size, blob);
445	talloc_free(aname);
446	return status;
447}
448
449/*
450  save a xattr with the given name
451*/
452NTSTATUS pvfs_xattr_save(struct pvfs_state *pvfs,
453			 const char *fname, int fd,
454			 const char *attr_prefix,
455			 const char *attr_name,
456			 const DATA_BLOB *blob)
457{
458	NTSTATUS status;
459	char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
460	if (aname == NULL) {
461		return NT_STATUS_NO_MEMORY;
462	}
463	status = push_xattr_blob(pvfs, aname, fname, fd, blob);
464	talloc_free(aname);
465	return status;
466}
467
468
469/*
470  probe for system support for xattrs
471*/
472void pvfs_xattr_probe(struct pvfs_state *pvfs)
473{
474	TALLOC_CTX *tmp_ctx = talloc_new(pvfs);
475	DATA_BLOB blob;
476	pull_xattr_blob(pvfs, tmp_ctx, "user.XattrProbe", pvfs->base_directory,
477			-1, 1, &blob);
478	pull_xattr_blob(pvfs, tmp_ctx, "security.XattrProbe", pvfs->base_directory,
479			-1, 1, &blob);
480	talloc_free(tmp_ctx);
481}
482