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