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