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