r26639: librpc: Pass iconv convenience on from RPC connection to NDR library, so...
[bbaumbach/samba-autobuild/.git] / source4 / ntvfs / posix / pvfs_xattr.c
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,
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 */
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 */
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 */
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 */
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         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 _PUBLIC_ NTSTATUS 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(global_loadparm), 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)
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_DosInfo2 *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                 info2 = &attrib.info.info2;
214                 name->dos.attrib = pvfs_attrib_normalise(info2->attrib, 
215                                                          name->st.st_mode);
216                 name->dos.ea_size = info2->ea_size;
217                 if (name->st.st_size == info2->size) {
218                         name->dos.alloc_size = 
219                                 pvfs_round_alloc_size(pvfs, info2->alloc_size);
220                 }
221                 if (!null_nttime(info2->create_time)) {
222                         name->dos.create_time = info2->create_time;
223                 }
224                 if (!null_nttime(info2->change_time)) {
225                         name->dos.change_time = info2->change_time;
226                 }
227                 name->dos.flags = info2->flags;
228                 if (name->dos.flags & XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME) {
229                         name->dos.write_time = info2->write_time;
230                 }
231                 break;
232
233         default:
234                 DEBUG(0,("ERROR: Unsupported xattr DosAttrib version %d on '%s'\n",
235                          attrib.version, name->full_name));
236                 talloc_free(mem_ctx);
237                 return NT_STATUS_INVALID_LEVEL;
238         }
239         talloc_free(mem_ctx);
240         
241         status = pvfs_stream_info(pvfs, name, fd);
242
243         return status;
244 }
245
246
247 /*
248   save the file attribute into the xattr
249 */
250 NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
251 {
252         struct xattr_DosAttrib attrib;
253         struct xattr_DosInfo2 *info2;
254
255         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
256                 return NT_STATUS_OK;
257         }
258
259         attrib.version = 2;
260         info2 = &attrib.info.info2;
261
262         name->dos.attrib = pvfs_attrib_normalise(name->dos.attrib, name->st.st_mode);
263
264         info2->attrib      = name->dos.attrib;
265         info2->ea_size     = name->dos.ea_size;
266         info2->size        = name->st.st_size;
267         info2->alloc_size  = name->dos.alloc_size;
268         info2->create_time = name->dos.create_time;
269         info2->change_time = name->dos.change_time;
270         info2->write_time  = name->dos.write_time;
271         info2->flags       = name->dos.flags;
272         info2->name        = "";
273
274         return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, 
275                                    XATTR_DOSATTRIB_NAME, &attrib, 
276                                    (ndr_push_flags_fn_t)ndr_push_xattr_DosAttrib);
277 }
278
279
280 /*
281   load the set of DOS EAs
282 */
283 NTSTATUS pvfs_doseas_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
284                           struct xattr_DosEAs *eas)
285 {
286         NTSTATUS status;
287         ZERO_STRUCTP(eas);
288         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
289                 return NT_STATUS_OK;
290         }
291         status = pvfs_xattr_ndr_load(pvfs, eas, name->full_name, fd, XATTR_DOSEAS_NAME,
292                                      eas, (ndr_pull_flags_fn_t)ndr_pull_xattr_DosEAs);
293         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
294                 return NT_STATUS_OK;
295         }
296         return status;
297 }
298
299 /*
300   save the set of DOS EAs
301 */
302 NTSTATUS pvfs_doseas_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
303                           struct xattr_DosEAs *eas)
304 {
305         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
306                 return NT_STATUS_OK;
307         }
308         return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, XATTR_DOSEAS_NAME, eas, 
309                                    (ndr_push_flags_fn_t)ndr_push_xattr_DosEAs);
310 }
311
312
313 /*
314   load the set of streams from extended attributes
315 */
316 NTSTATUS pvfs_streams_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
317                            struct xattr_DosStreams *streams)
318 {
319         NTSTATUS status;
320         ZERO_STRUCTP(streams);
321         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
322                 return NT_STATUS_OK;
323         }
324         status = pvfs_xattr_ndr_load(pvfs, streams, name->full_name, fd, 
325                                      XATTR_DOSSTREAMS_NAME,
326                                      streams, 
327                                      (ndr_pull_flags_fn_t)ndr_pull_xattr_DosStreams);
328         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
329                 return NT_STATUS_OK;
330         }
331         return status;
332 }
333
334 /*
335   save the set of streams into filesystem xattr
336 */
337 NTSTATUS pvfs_streams_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
338                            struct xattr_DosStreams *streams)
339 {
340         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
341                 return NT_STATUS_OK;
342         }
343         return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, 
344                                    XATTR_DOSSTREAMS_NAME, 
345                                    streams, 
346                                    (ndr_push_flags_fn_t)ndr_push_xattr_DosStreams);
347 }
348
349
350 /*
351   load the current ACL from extended attributes
352 */
353 NTSTATUS pvfs_acl_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
354                        struct xattr_NTACL *acl)
355 {
356         NTSTATUS status;
357         ZERO_STRUCTP(acl);
358         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
359                 return NT_STATUS_NOT_FOUND;
360         }
361         status = pvfs_xattr_ndr_load(pvfs, acl, name->full_name, fd, 
362                                      XATTR_NTACL_NAME,
363                                      acl, 
364                                      (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
365         return status;
366 }
367
368 /*
369   save the acl for a file into filesystem xattr
370 */
371 NTSTATUS pvfs_acl_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
372                        struct xattr_NTACL *acl)
373 {
374         NTSTATUS status;
375         void *privs;
376
377         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
378                 return NT_STATUS_OK;
379         }
380
381         /* this xattr is in the "system" namespace, so we need
382            admin privileges to set it */
383         privs = root_privileges();
384         status = pvfs_xattr_ndr_save(pvfs, name->full_name, fd, 
385                                      XATTR_NTACL_NAME, 
386                                      acl, 
387                                      (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
388         talloc_free(privs);
389         return status;
390 }
391
392 /*
393   create a zero length xattr with the given name
394 */
395 NTSTATUS pvfs_xattr_create(struct pvfs_state *pvfs, 
396                            const char *fname, int fd,
397                            const char *attr_prefix,
398                            const char *attr_name)
399 {
400         NTSTATUS status;
401         DATA_BLOB blob = data_blob(NULL, 0);
402         char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
403         if (aname == NULL) {
404                 return NT_STATUS_NO_MEMORY;
405         }
406         status = push_xattr_blob(pvfs, aname, fname, fd, &blob);
407         talloc_free(aname);
408         return status;
409 }
410
411
412 /*
413   delete a xattr with the given name
414 */
415 NTSTATUS pvfs_xattr_delete(struct pvfs_state *pvfs, 
416                            const char *fname, int fd,
417                            const char *attr_prefix,
418                            const char *attr_name)
419 {
420         NTSTATUS status;
421         char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
422         if (aname == NULL) {
423                 return NT_STATUS_NO_MEMORY;
424         }
425         status = delete_xattr(pvfs, aname, fname, fd);
426         talloc_free(aname);
427         return status;
428 }
429
430 /*
431   load a xattr with the given name
432 */
433 NTSTATUS pvfs_xattr_load(struct pvfs_state *pvfs, 
434                          TALLOC_CTX *mem_ctx,
435                          const char *fname, int fd,
436                          const char *attr_prefix,
437                          const char *attr_name,
438                          size_t estimated_size,
439                          DATA_BLOB *blob)
440 {
441         NTSTATUS status;
442         char *aname = talloc_asprintf(mem_ctx, "%s%s", attr_prefix, attr_name);
443         if (aname == NULL) {
444                 return NT_STATUS_NO_MEMORY;
445         }
446         status = pull_xattr_blob(pvfs, mem_ctx, aname, fname, fd, estimated_size, blob);
447         talloc_free(aname);
448         return status;
449 }
450
451 /*
452   save a xattr with the given name
453 */
454 NTSTATUS pvfs_xattr_save(struct pvfs_state *pvfs, 
455                          const char *fname, int fd,
456                          const char *attr_prefix,
457                          const char *attr_name,
458                          const DATA_BLOB *blob)
459 {
460         NTSTATUS status;
461         char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
462         if (aname == NULL) {
463                 return NT_STATUS_NO_MEMORY;
464         }
465         status = push_xattr_blob(pvfs, aname, fname, fd, blob);
466         talloc_free(aname);
467         return status;
468 }
469
470
471 /*
472   probe for system support for xattrs
473 */
474 void pvfs_xattr_probe(struct pvfs_state *pvfs)
475 {
476         TALLOC_CTX *tmp_ctx = talloc_new(pvfs);
477         DATA_BLOB blob;
478         pull_xattr_blob(pvfs, tmp_ctx, "user.XattrProbe", pvfs->base_directory, 
479                         -1, 1, &blob);
480         pull_xattr_blob(pvfs, tmp_ctx, "security.XattrProbe", pvfs->base_directory, 
481                         -1, 1, &blob);
482         talloc_free(tmp_ctx);
483 }