/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- pull_xattr_blob
- push_xattr_blob
- delete_xattr
- pvfs_xattr_unlink_hook
- pvfs_xattr_ndr_load
- pvfs_xattr_ndr_save
- pvfs_dosattrib_load
- pvfs_dosattrib_save
- pvfs_doseas_load
- pvfs_doseas_save
- pvfs_streams_load
- pvfs_streams_save
- pvfs_acl_load
- pvfs_acl_save
- pvfs_xattr_create
- pvfs_xattr_delete
- pvfs_xattr_load
- pvfs_xattr_save
- pvfs_xattr_probe
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 */
31 static NTSTATUS pull_xattr_blob(struct pvfs_state *pvfs,
/* [<][>][^][v][top][bottom][index][help] */
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 */
64 static NTSTATUS push_xattr_blob(struct pvfs_state *pvfs,
/* [<][>][^][v][top][bottom][index][help] */
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 */
80 static NTSTATUS delete_xattr(struct pvfs_state *pvfs, const char *attr_name,
/* [<][>][^][v][top][bottom][index][help] */
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 */
92 NTSTATUS pvfs_xattr_unlink_hook(struct pvfs_state *pvfs, const char *fname)
/* [<][>][^][v][top][bottom][index][help] */
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 */
104 NTSTATUS pvfs_xattr_ndr_load(struct pvfs_state *pvfs,
/* [<][>][^][v][top][bottom][index][help] */
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 */
134 NTSTATUS pvfs_xattr_ndr_save(struct pvfs_state *pvfs,
/* [<][>][^][v][top][bottom][index][help] */
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 */
159 NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
/* [<][>][^][v][top][bottom][index][help] */
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 */
251 NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
/* [<][>][^][v][top][bottom][index][help] */
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 */
281 NTSTATUS pvfs_doseas_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
/* [<][>][^][v][top][bottom][index][help] */
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 */
300 NTSTATUS pvfs_doseas_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
/* [<][>][^][v][top][bottom][index][help] */
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 */
314 NTSTATUS pvfs_streams_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
/* [<][>][^][v][top][bottom][index][help] */
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 */
335 NTSTATUS pvfs_streams_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
/* [<][>][^][v][top][bottom][index][help] */
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 */
351 NTSTATUS pvfs_acl_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
/* [<][>][^][v][top][bottom][index][help] */
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 */
369 NTSTATUS pvfs_acl_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
/* [<][>][^][v][top][bottom][index][help] */
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 */
393 NTSTATUS pvfs_xattr_create(struct pvfs_state *pvfs,
/* [<][>][^][v][top][bottom][index][help] */
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 */
413 NTSTATUS pvfs_xattr_delete(struct pvfs_state *pvfs,
/* [<][>][^][v][top][bottom][index][help] */
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 */
431 NTSTATUS pvfs_xattr_load(struct pvfs_state *pvfs,
/* [<][>][^][v][top][bottom][index][help] */
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 */
452 NTSTATUS pvfs_xattr_save(struct pvfs_state *pvfs,
/* [<][>][^][v][top][bottom][index][help] */
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 */
472 void pvfs_xattr_probe(struct pvfs_state *pvfs)
/* [<][>][^][v][top][bottom][index][help] */
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 }