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