r19507: Merge my DSO fixes branch. Building Samba's libraries as shared libraries
[tprouty/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 "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             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
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 }