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