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