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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "vfs_posix.h"
25 #include "lib/util/unix_privs.h"
26 #include "librpc/gen_ndr/ndr_xattr.h"
27
28 /*
29 pull a xattr as a blob
30 */
pull_xattr_blob(struct pvfs_state * pvfs,TALLOC_CTX * mem_ctx,const char * attr_name,const char * fname,int fd,size_t estimated_size,DATA_BLOB * blob)31 static 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(5,("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 */
push_xattr_blob(struct pvfs_state * pvfs,const char * attr_name,const char * fname,int fd,const DATA_BLOB * blob)64 static 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 */
delete_xattr(struct pvfs_state * pvfs,const char * attr_name,const char * fname,int fd)80 static 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 */
pvfs_xattr_unlink_hook(struct pvfs_state * pvfs,const char * fname)92 NTSTATUS 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 */
pvfs_xattr_ndr_load(struct pvfs_state * pvfs,TALLOC_CTX * mem_ctx,const char * fname,int fd,const char * attr_name,void * p,void * pull_fn)104 _PUBLIC_ NTSTATUS 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
112 status = pull_xattr_blob(pvfs, mem_ctx, attr_name, fname,
113 fd, XATTR_DOSATTRIB_ESTIMATED_SIZE, &blob);
114 if (!NT_STATUS_IS_OK(status)) {
115 return status;
116 }
117
118 /* pull the blob */
119 status = ndr_pull_struct_blob(&blob, mem_ctx, p, (ndr_pull_flags_fn_t)pull_fn);
120
121 data_blob_free(&blob);
122
123 return status;
124 }
125
126 /*
127 save a NDR structure into a xattr
128 */
pvfs_xattr_ndr_save(struct pvfs_state * pvfs,const char * fname,int fd,const char * attr_name,void * p,void * push_fn)129 _PUBLIC_ NTSTATUS pvfs_xattr_ndr_save(struct pvfs_state *pvfs,
130 const char *fname, int fd, const char *attr_name,
131 void *p, void *push_fn)
132 {
133 TALLOC_CTX *mem_ctx = talloc_new(NULL);
134 DATA_BLOB blob;
135 NTSTATUS status;
136
137 status = ndr_push_struct_blob(&blob, mem_ctx, p, (ndr_push_flags_fn_t)push_fn);
138 if (!NT_STATUS_IS_OK(status)) {
139 talloc_free(mem_ctx);
140 return status;
141 }
142
143 status = push_xattr_blob(pvfs, attr_name, fname, fd, &blob);
144 talloc_free(mem_ctx);
145
146 return status;
147 }
148
149
150 /*
151 fill in file attributes from extended attributes
152 */
pvfs_dosattrib_load(struct pvfs_state * pvfs,struct pvfs_filename * name,int fd)153 NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
154 {
155 NTSTATUS status;
156 struct xattr_DosAttrib attrib;
157 TALLOC_CTX *mem_ctx = talloc_new(name);
158 struct xattr_DosInfo1 *info1;
159 struct xattr_DosInfo2 *info2;
160
161 if (name->stream_name != NULL) {
162 name->stream_exists = False;
163 } else {
164 name->stream_exists = True;
165 }
166
167 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
168 return NT_STATUS_OK;
169 }
170
171 status = pvfs_xattr_ndr_load(pvfs, mem_ctx, name->full_name,
172 fd, XATTR_DOSATTRIB_NAME,
173 &attrib,
174 (ndr_pull_flags_fn_t)ndr_pull_xattr_DosAttrib);
175
176 /* not having a DosAttrib is not an error */
177 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
178 talloc_free(mem_ctx);
179 return pvfs_stream_info(pvfs, name, fd);
180 }
181
182 if (!NT_STATUS_IS_OK(status)) {
183 talloc_free(mem_ctx);
184 return status;
185 }
186
187 switch (attrib.version) {
188 case 1:
189 info1 = &attrib.info.info1;
190 name->dos.attrib = pvfs_attrib_normalise(info1->attrib,
191 name->st.st_mode);
192 name->dos.ea_size = info1->ea_size;
193 if (name->st.st_size == info1->size) {
194 name->dos.alloc_size =
195 pvfs_round_alloc_size(pvfs, info1->alloc_size);
196 }
197 if (!null_nttime(info1->create_time)) {
198 name->dos.create_time = info1->create_time;
199 }
200 if (!null_nttime(info1->change_time)) {
201 name->dos.change_time = info1->change_time;
202 }
203 name->dos.flags = 0;
204 break;
205
206 case 2:
207 info2 = &attrib.info.info2;
208 name->dos.attrib = pvfs_attrib_normalise(info2->attrib,
209 name->st.st_mode);
210 name->dos.ea_size = info2->ea_size;
211 if (name->st.st_size == info2->size) {
212 name->dos.alloc_size =
213 pvfs_round_alloc_size(pvfs, info2->alloc_size);
214 }
215 if (!null_nttime(info2->create_time)) {
216 name->dos.create_time = info2->create_time;
217 }
218 if (!null_nttime(info2->change_time)) {
219 name->dos.change_time = info2->change_time;
220 }
221 name->dos.flags = info2->flags;
222 if (name->dos.flags & XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME) {
223 name->dos.write_time = info2->write_time;
224 }
225 break;
226
227 default:
228 DEBUG(0,("ERROR: Unsupported xattr DosAttrib version %d on '%s'\n",
229 attrib.version, name->full_name));
230 talloc_free(mem_ctx);
231 return NT_STATUS_INVALID_LEVEL;
232 }
233 talloc_free(mem_ctx);
234
235 status = pvfs_stream_info(pvfs, name, fd);
236
237 return status;
238 }
239
240
241 /*
242 save the file attribute into the xattr
243 */
pvfs_dosattrib_save(struct pvfs_state * pvfs,struct pvfs_filename * name,int fd)244 NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
245 {
246 struct xattr_DosAttrib attrib;
247 struct xattr_DosInfo2 *info2;
248
249 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
250 return NT_STATUS_OK;
251 }
252
253 attrib.version = 2;
254 info2 = &attrib.info.info2;
255
256 name->dos.attrib = pvfs_attrib_normalise(name->dos.attrib, name->st.st_mode);
257
258 info2->attrib = name->dos.attrib;
259 info2->ea_size = name->dos.ea_size;
260 info2->size = name->st.st_size;
261 info2->alloc_size = name->dos.alloc_size;
262 info2->create_time = name->dos.create_time;
263 info2->change_time = name->dos.change_time;
264 info2->write_time = name->dos.write_time;
265 info2->flags = name->dos.flags;
266 info2->name = "";
267
268 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
269 XATTR_DOSATTRIB_NAME, &attrib,
270 (ndr_push_flags_fn_t)ndr_push_xattr_DosAttrib);
271 }
272
273
274 /*
275 load the set of DOS EAs
276 */
pvfs_doseas_load(struct pvfs_state * pvfs,struct pvfs_filename * name,int fd,struct xattr_DosEAs * eas)277 NTSTATUS pvfs_doseas_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
278 struct xattr_DosEAs *eas)
279 {
280 NTSTATUS status;
281 ZERO_STRUCTP(eas);
282 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
283 return NT_STATUS_OK;
284 }
285 status = pvfs_xattr_ndr_load(pvfs, eas, name->full_name, fd, XATTR_DOSEAS_NAME,
286 eas, (ndr_pull_flags_fn_t)ndr_pull_xattr_DosEAs);
287 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
288 return NT_STATUS_OK;
289 }
290 return status;
291 }
292
293 /*
294 save the set of DOS EAs
295 */
pvfs_doseas_save(struct pvfs_state * pvfs,struct pvfs_filename * name,int fd,struct xattr_DosEAs * eas)296 NTSTATUS pvfs_doseas_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
297 struct xattr_DosEAs *eas)
298 {
299 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
300 return NT_STATUS_OK;
301 }
302 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, XATTR_DOSEAS_NAME, eas,
303 (ndr_push_flags_fn_t)ndr_push_xattr_DosEAs);
304 }
305
306
307 /*
308 load the set of streams from extended attributes
309 */
pvfs_streams_load(struct pvfs_state * pvfs,struct pvfs_filename * name,int fd,struct xattr_DosStreams * streams)310 NTSTATUS pvfs_streams_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
311 struct xattr_DosStreams *streams)
312 {
313 NTSTATUS status;
314 ZERO_STRUCTP(streams);
315 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
316 return NT_STATUS_OK;
317 }
318 status = pvfs_xattr_ndr_load(pvfs, streams, name->full_name, fd,
319 XATTR_DOSSTREAMS_NAME,
320 streams,
321 (ndr_pull_flags_fn_t)ndr_pull_xattr_DosStreams);
322 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
323 return NT_STATUS_OK;
324 }
325 return status;
326 }
327
328 /*
329 save the set of streams into filesystem xattr
330 */
pvfs_streams_save(struct pvfs_state * pvfs,struct pvfs_filename * name,int fd,struct xattr_DosStreams * streams)331 NTSTATUS pvfs_streams_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
332 struct xattr_DosStreams *streams)
333 {
334 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
335 return NT_STATUS_OK;
336 }
337 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
338 XATTR_DOSSTREAMS_NAME,
339 streams,
340 (ndr_push_flags_fn_t)ndr_push_xattr_DosStreams);
341 }
342
343
344 /*
345 load the current ACL from extended attributes
346 */
pvfs_acl_load(struct pvfs_state * pvfs,struct pvfs_filename * name,int fd,struct xattr_NTACL * acl)347 NTSTATUS pvfs_acl_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
348 struct xattr_NTACL *acl)
349 {
350 NTSTATUS status;
351 ZERO_STRUCTP(acl);
352 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
353 return NT_STATUS_NOT_FOUND;
354 }
355 status = pvfs_xattr_ndr_load(pvfs, acl, name->full_name, fd,
356 XATTR_NTACL_NAME,
357 acl,
358 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
359 return status;
360 }
361
362 /*
363 save the acl for a file into filesystem xattr
364 */
pvfs_acl_save(struct pvfs_state * pvfs,struct pvfs_filename * name,int fd,struct xattr_NTACL * acl)365 NTSTATUS pvfs_acl_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
366 struct xattr_NTACL *acl)
367 {
368 NTSTATUS status;
369 void *privs;
370
371 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
372 return NT_STATUS_OK;
373 }
374
375 /* this xattr is in the "system" namespace, so we need
376 admin privileges to set it */
377 privs = root_privileges();
378 status = pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
379 XATTR_NTACL_NAME,
380 acl,
381 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
382 talloc_free(privs);
383 return status;
384 }
385
386 /*
387 create a zero length xattr with the given name
388 */
pvfs_xattr_create(struct pvfs_state * pvfs,const char * fname,int fd,const char * attr_prefix,const char * attr_name)389 NTSTATUS pvfs_xattr_create(struct pvfs_state *pvfs,
390 const char *fname, int fd,
391 const char *attr_prefix,
392 const char *attr_name)
393 {
394 NTSTATUS status;
395 DATA_BLOB blob = data_blob(NULL, 0);
396 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
397 if (aname == NULL) {
398 return NT_STATUS_NO_MEMORY;
399 }
400 status = push_xattr_blob(pvfs, aname, fname, fd, &blob);
401 talloc_free(aname);
402 return status;
403 }
404
405
406 /*
407 delete a xattr with the given name
408 */
pvfs_xattr_delete(struct pvfs_state * pvfs,const char * fname,int fd,const char * attr_prefix,const char * attr_name)409 NTSTATUS pvfs_xattr_delete(struct pvfs_state *pvfs,
410 const char *fname, int fd,
411 const char *attr_prefix,
412 const char *attr_name)
413 {
414 NTSTATUS status;
415 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
416 if (aname == NULL) {
417 return NT_STATUS_NO_MEMORY;
418 }
419 status = delete_xattr(pvfs, aname, fname, fd);
420 talloc_free(aname);
421 return status;
422 }
423
424 /*
425 load a xattr with the given name
426 */
pvfs_xattr_load(struct pvfs_state * pvfs,TALLOC_CTX * mem_ctx,const char * fname,int fd,const char * attr_prefix,const char * attr_name,size_t estimated_size,DATA_BLOB * blob)427 NTSTATUS pvfs_xattr_load(struct pvfs_state *pvfs,
428 TALLOC_CTX *mem_ctx,
429 const char *fname, int fd,
430 const char *attr_prefix,
431 const char *attr_name,
432 size_t estimated_size,
433 DATA_BLOB *blob)
434 {
435 NTSTATUS status;
436 char *aname = talloc_asprintf(mem_ctx, "%s%s", attr_prefix, attr_name);
437 if (aname == NULL) {
438 return NT_STATUS_NO_MEMORY;
439 }
440 status = pull_xattr_blob(pvfs, mem_ctx, aname, fname, fd, estimated_size, blob);
441 talloc_free(aname);
442 return status;
443 }
444
445 /*
446 save a xattr with the given name
447 */
pvfs_xattr_save(struct pvfs_state * pvfs,const char * fname,int fd,const char * attr_prefix,const char * attr_name,const DATA_BLOB * blob)448 NTSTATUS pvfs_xattr_save(struct pvfs_state *pvfs,
449 const char *fname, int fd,
450 const char *attr_prefix,
451 const char *attr_name,
452 const DATA_BLOB *blob)
453 {
454 NTSTATUS status;
455 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
456 if (aname == NULL) {
457 return NT_STATUS_NO_MEMORY;
458 }
459 status = push_xattr_blob(pvfs, aname, fname, fd, blob);
460 talloc_free(aname);
461 return status;
462 }
463
464
465 /*
466 probe for system support for xattrs
467 */
pvfs_xattr_probe(struct pvfs_state * pvfs)468 void pvfs_xattr_probe(struct pvfs_state *pvfs)
469 {
470 TALLOC_CTX *tmp_ctx = talloc_new(pvfs);
471 DATA_BLOB blob;
472 pull_xattr_blob(pvfs, tmp_ctx, "user.XattrProbe", pvfs->base_directory,
473 -1, 1, &blob);
474 pull_xattr_blob(pvfs, tmp_ctx, "security.XattrProbe", pvfs->base_directory,
475 -1, 1, &blob);
476 talloc_free(tmp_ctx);
477 }
478