~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/ntvfs/posix/pvfs_xattr.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
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(2,("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
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
        enum ndr_err_code ndr_err;
 
112
 
 
113
        status = pull_xattr_blob(pvfs, mem_ctx, attr_name, fname, 
 
114
                                 fd, XATTR_DOSATTRIB_ESTIMATED_SIZE, &blob);
 
115
        if (!NT_STATUS_IS_OK(status)) {
 
116
                return status;
 
117
        }
 
118
 
 
119
        /* pull the blob */
 
120
        ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, lp_iconv_convenience(pvfs->ntvfs->ctx->lp_ctx), 
 
121
                                       p, (ndr_pull_flags_fn_t)pull_fn);
 
122
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 
123
                return ndr_map_error2ntstatus(ndr_err);
 
124
        }
 
125
 
 
126
        data_blob_free(&blob);
 
127
 
 
128
        return NT_STATUS_OK;
 
129
}
 
130
 
 
131
/*
 
132
  save a NDR structure into a xattr
 
133
*/
 
134
NTSTATUS pvfs_xattr_ndr_save(struct pvfs_state *pvfs,
 
135
                             const char *fname, int fd, const char *attr_name, 
 
136
                             void *p, void *push_fn)
 
137
{
 
138
        TALLOC_CTX *mem_ctx = talloc_new(NULL);
 
139
        DATA_BLOB blob;
 
140
        NTSTATUS status;
 
141
        enum ndr_err_code ndr_err;
 
142
 
 
143
        ndr_err = ndr_push_struct_blob(&blob, mem_ctx, lp_iconv_convenience(pvfs->ntvfs->ctx->lp_ctx), p, (ndr_push_flags_fn_t)push_fn);
 
144
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 
145
                talloc_free(mem_ctx);
 
146
                return ndr_map_error2ntstatus(ndr_err);
 
147
        }
 
148
 
 
149
        status = push_xattr_blob(pvfs, attr_name, fname, fd, &blob);
 
150
        talloc_free(mem_ctx);
 
151
 
 
152
        return status;
 
153
}
 
154
 
 
155
 
 
156
/*
 
157
  fill in file attributes from extended attributes
 
158
*/
 
159
NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
 
160
{
 
161
        NTSTATUS status;
 
162
        struct xattr_DosAttrib attrib;
 
163
        TALLOC_CTX *mem_ctx = talloc_new(name);
 
164
        struct xattr_DosInfo1 *info1;
 
165
        struct xattr_DosInfo2Old *info2;
 
166
 
 
167
        if (name->stream_name != NULL) {
 
168
                name->stream_exists = false;
 
169
        } else {
 
170
                name->stream_exists = true;
 
171
        }
 
172
 
 
173
        if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
 
174
                return NT_STATUS_OK;
 
175
        }
 
176
 
 
177
        status = pvfs_xattr_ndr_load(pvfs, mem_ctx, name->full_name, 
 
178
                                     fd, XATTR_DOSATTRIB_NAME,
 
179
                                     &attrib, 
 
180
                                     (ndr_pull_flags_fn_t)ndr_pull_xattr_DosAttrib);
 
181
 
 
182
        /* not having a DosAttrib is not an error */
 
183
        if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
 
184
                talloc_free(mem_ctx);
 
185
                return pvfs_stream_info(pvfs, name, fd);
 
186
        }
 
187
 
 
188
        if (!NT_STATUS_IS_OK(status)) {
 
189
                talloc_free(mem_ctx);
 
190
                return status;
 
191
        }
 
192
 
 
193
        switch (attrib.version) {
 
194
        case 1:
 
195
                info1 = &attrib.info.info1;
 
196
                name->dos.attrib = pvfs_attrib_normalise(info1->attrib, 
 
197
                                                         name->st.st_mode);
 
198
                name->dos.ea_size = info1->ea_size;
 
199
                if (name->st.st_size == info1->size) {
 
200
                        name->dos.alloc_size = 
 
201
                                pvfs_round_alloc_size(pvfs, info1->alloc_size);
 
202
                }
 
203
                if (!null_nttime(info1->create_time)) {
 
204
                        name->dos.create_time = info1->create_time;
 
205
                }
 
206
                if (!null_nttime(info1->change_time)) {
 
207
                        name->dos.change_time = info1->change_time;
 
208
                }
 
209
                name->dos.flags = 0;
 
210
                break;
 
211
 
 
212
        case 2:
 
213
                /*
 
214
                 * Note: This is only used to parse existing values from disk
 
215
                 *       We use xattr_DosInfo1 again for storing new values
 
216
                 */
 
217
                info2 = &attrib.info.oldinfo2;
 
218
                name->dos.attrib = pvfs_attrib_normalise(info2->attrib, 
 
219
                                                         name->st.st_mode);
 
220
                name->dos.ea_size = info2->ea_size;
 
221
                if (name->st.st_size == info2->size) {
 
222
                        name->dos.alloc_size = 
 
223
                                pvfs_round_alloc_size(pvfs, info2->alloc_size);
 
224
                }
 
225
                if (!null_nttime(info2->create_time)) {
 
226
                        name->dos.create_time = info2->create_time;
 
227
                }
 
228
                if (!null_nttime(info2->change_time)) {
 
229
                        name->dos.change_time = info2->change_time;
 
230
                }
 
231
                name->dos.flags = info2->flags;
 
232
                break;
 
233
 
 
234
        default:
 
235
                DEBUG(0,("ERROR: Unsupported xattr DosAttrib version %d on '%s'\n",
 
236
                         attrib.version, name->full_name));
 
237
                talloc_free(mem_ctx);
 
238
                return NT_STATUS_INVALID_LEVEL;
 
239
        }
 
240
        talloc_free(mem_ctx);
 
241
        
 
242
        status = pvfs_stream_info(pvfs, name, fd);
 
243
 
 
244
        return status;
 
245
}
 
246
 
 
247
 
 
248
/*
 
249
  save the file attribute into the xattr
 
250
*/
 
251
NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
 
252
{
 
253
        struct xattr_DosAttrib attrib;
 
254
        struct xattr_DosInfo1 *info1;
 
255
 
 
256
        if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
 
257
                return NT_STATUS_OK;
 
258
        }
 
259
 
 
260
        attrib.version = 1;
 
261
        info1 = &attrib.info.info1;
 
262
 
 
263
        name->dos.attrib = pvfs_attrib_normalise(name->dos.attrib, name->st.st_mode);
 
264
 
 
265
        info1->attrib      = name->dos.attrib;
 
266
        info1->ea_size     = name->dos.ea_size;
 
267
        info1->size        = name->st.st_size;
 
268
        info1->alloc_size  = name->dos.alloc_size;
 
269
        info1->create_time = name->dos.create_time;
 
270
        info1->change_time = name->dos.change_time;
 
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
}