~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/modules/vfs_acl_tdb.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
 * Store Windows ACLs in a tdb.
 
3
 *
 
4
 * Copyright (C) Volker Lendecke, 2008
 
5
 * Copyright (C) Jeremy Allison, 2008
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 3 of the License, or
 
10
 * (at your option) any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 
19
 */
 
20
 
 
21
/* NOTE: This is an experimental module, not yet finished. JRA. */
 
22
 
 
23
#include "includes.h"
 
24
#include "librpc/gen_ndr/xattr.h"
 
25
#include "librpc/gen_ndr/ndr_xattr.h"
 
26
 
 
27
#undef DBGC_CLASS
 
28
#define DBGC_CLASS DBGC_VFS
 
29
 
 
30
static unsigned int ref_count;
 
31
static struct db_context *acl_db;
 
32
 
 
33
/*******************************************************************
 
34
 Open acl_db if not already open, increment ref count.
 
35
*******************************************************************/
 
36
 
 
37
static bool acl_tdb_init(struct db_context **pp_db)
 
38
{
 
39
        char *dbname;
 
40
 
 
41
        if (acl_db) {
 
42
                *pp_db = acl_db;
 
43
                ref_count++;
 
44
                return true;
 
45
        }
 
46
 
 
47
        dbname = state_path("file_ntacls.tdb");
 
48
 
 
49
        if (dbname == NULL) {
 
50
                errno = ENOSYS;
 
51
                return false;
 
52
        }
 
53
 
 
54
        become_root();
 
55
        *pp_db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
 
56
        unbecome_root();
 
57
 
 
58
        if (*pp_db == NULL) {
 
59
#if defined(ENOTSUP)
 
60
                errno = ENOTSUP;
 
61
#else
 
62
                errno = ENOSYS;
 
63
#endif
 
64
                TALLOC_FREE(dbname);
 
65
                return false;
 
66
        }
 
67
 
 
68
        ref_count++;
 
69
        TALLOC_FREE(dbname);
 
70
        return true;
 
71
}
 
72
 
 
73
/*******************************************************************
 
74
 Lower ref count and close acl_db if zero.
 
75
*******************************************************************/
 
76
 
 
77
static void free_acl_tdb_data(void **pptr)
 
78
{
 
79
        struct db_context **pp_db = (struct db_context **)pptr;
 
80
 
 
81
        ref_count--;
 
82
        if (ref_count == 0) {
 
83
                TALLOC_FREE(*pp_db);
 
84
                acl_db = NULL;
 
85
        }
 
86
}
 
87
 
 
88
/*******************************************************************
 
89
 Fetch_lock the tdb acl record for a file
 
90
*******************************************************************/
 
91
 
 
92
static struct db_record *acl_tdb_lock(TALLOC_CTX *mem_ctx,
 
93
                                        struct db_context *db,
 
94
                                        const struct file_id *id)
 
95
{
 
96
        uint8 id_buf[16];
 
97
 
 
98
        /* For backwards compatibility only store the dev/inode. */
 
99
        push_file_id_16((char *)id_buf, id);
 
100
        return db->fetch_locked(db,
 
101
                                mem_ctx,
 
102
                                make_tdb_data(id_buf,
 
103
                                        sizeof(id_buf)));
 
104
}
 
105
 
 
106
/*******************************************************************
 
107
 Delete the tdb acl record for a file
 
108
*******************************************************************/
 
109
 
 
110
static NTSTATUS acl_tdb_delete(vfs_handle_struct *handle,
 
111
                                struct db_context *db,
 
112
                                SMB_STRUCT_STAT *psbuf)
 
113
{
 
114
        NTSTATUS status;
 
115
        struct file_id id = vfs_file_id_from_sbuf(handle->conn, psbuf);
 
116
        struct db_record *rec = acl_tdb_lock(talloc_tos(), db, &id);
 
117
 
 
118
        /*
 
119
         * If rec == NULL there's not much we can do about it
 
120
         */
 
121
 
 
122
        if (rec == NULL) {
 
123
                DEBUG(10,("acl_tdb_delete: rec == NULL\n"));
 
124
                TALLOC_FREE(rec);
 
125
                return NT_STATUS_OK;
 
126
        }
 
127
 
 
128
        status = rec->delete_rec(rec);
 
129
        TALLOC_FREE(rec);
 
130
        return status;
 
131
}
 
132
 
 
133
/*******************************************************************
 
134
 Parse out a struct security_descriptor from a DATA_BLOB.
 
135
*******************************************************************/
 
136
 
 
137
static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
 
138
                                uint32 security_info,
 
139
                                struct security_descriptor **ppdesc)
 
140
{
 
141
        TALLOC_CTX *ctx = talloc_tos();
 
142
        struct xattr_NTACL xacl;
 
143
        enum ndr_err_code ndr_err;
 
144
        size_t sd_size;
 
145
 
 
146
        ndr_err = ndr_pull_struct_blob(pblob, ctx, NULL, &xacl,
 
147
                        (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
 
148
 
 
149
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 
150
                DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
 
151
                        ndr_errstr(ndr_err)));
 
152
                return ndr_map_error2ntstatus(ndr_err);;
 
153
        }
 
154
 
 
155
        if (xacl.version != 2) {
 
156
                return NT_STATUS_REVISION_MISMATCH;
 
157
        }
 
158
 
 
159
        *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION, xacl.info.sd_hs->sd->type | SEC_DESC_SELF_RELATIVE,
 
160
                        (security_info & OWNER_SECURITY_INFORMATION)
 
161
                        ? xacl.info.sd_hs->sd->owner_sid : NULL,
 
162
                        (security_info & GROUP_SECURITY_INFORMATION)
 
163
                        ? xacl.info.sd_hs->sd->group_sid : NULL,
 
164
                        (security_info & SACL_SECURITY_INFORMATION)
 
165
                        ? xacl.info.sd_hs->sd->sacl : NULL,
 
166
                        (security_info & DACL_SECURITY_INFORMATION)
 
167
                        ? xacl.info.sd_hs->sd->dacl : NULL,
 
168
                        &sd_size);
 
169
 
 
170
        TALLOC_FREE(xacl.info.sd);
 
171
 
 
172
        return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
 
173
}
 
174
 
 
175
/*******************************************************************
 
176
 Pull a security descriptor into a DATA_BLOB from a tdb store.
 
177
*******************************************************************/
 
178
 
 
179
static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
 
180
                        vfs_handle_struct *handle,
 
181
                        files_struct *fsp,
 
182
                        const char *name,
 
183
                        DATA_BLOB *pblob)
 
184
{
 
185
        uint8 id_buf[16];
 
186
        TDB_DATA data;
 
187
        struct file_id id;
 
188
        struct db_context *db;
 
189
        int ret = -1;
 
190
        SMB_STRUCT_STAT sbuf;
 
191
 
 
192
        SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
 
193
                return NT_STATUS_INTERNAL_DB_CORRUPTION);
 
194
 
 
195
        if (fsp && fsp->fh->fd != -1) {
 
196
                ret = SMB_VFS_FSTAT(fsp, &sbuf);
 
197
        } else {
 
198
                if (fsp && fsp->posix_open) {
 
199
                        ret = SMB_VFS_LSTAT(handle->conn, name, &sbuf);
 
200
                } else {
 
201
                        ret = SMB_VFS_STAT(handle->conn, name, &sbuf);
 
202
                }
 
203
        }
 
204
 
 
205
        if (ret == -1) {
 
206
                return map_nt_error_from_unix(errno);
 
207
        }
 
208
 
 
209
        id = vfs_file_id_from_sbuf(handle->conn, &sbuf);
 
210
 
 
211
        /* For backwards compatibility only store the dev/inode. */
 
212
        push_file_id_16((char *)id_buf, &id);
 
213
 
 
214
        if (db->fetch(db,
 
215
                        ctx,
 
216
                        make_tdb_data(id_buf, sizeof(id_buf)),
 
217
                        &data) == -1) {
 
218
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
219
        }
 
220
 
 
221
        pblob->data = data.dptr;
 
222
        pblob->length = data.dsize;
 
223
 
 
224
        DEBUG(10,("get_acl_blob: returned %u bytes from file %s\n",
 
225
                (unsigned int)data.dsize, name ));
 
226
 
 
227
        if (pblob->length == 0 || pblob->data == NULL) {
 
228
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
 
229
        }
 
230
        return NT_STATUS_OK;
 
231
}
 
232
 
 
233
/*******************************************************************
 
234
 Create a DATA_BLOB from a security descriptor.
 
235
*******************************************************************/
 
236
 
 
237
static NTSTATUS create_acl_blob(const struct security_descriptor *psd, DATA_BLOB *pblob)
 
238
{
 
239
        struct xattr_NTACL xacl;
 
240
        struct security_descriptor_hash sd_hs;
 
241
        enum ndr_err_code ndr_err;
 
242
        TALLOC_CTX *ctx = talloc_tos();
 
243
 
 
244
        ZERO_STRUCT(xacl);
 
245
        ZERO_STRUCT(sd_hs);
 
246
 
 
247
        xacl.version = 2;
 
248
        xacl.info.sd_hs = &sd_hs;
 
249
        xacl.info.sd_hs->sd = CONST_DISCARD(struct security_descriptor *, psd);
 
250
        memset(&xacl.info.sd_hs->hash[0], '\0', 16);
 
251
 
 
252
        ndr_err = ndr_push_struct_blob(
 
253
                        pblob, ctx, NULL, &xacl,
 
254
                        (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
 
255
 
 
256
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 
257
                DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
 
258
                        ndr_errstr(ndr_err)));
 
259
                return ndr_map_error2ntstatus(ndr_err);;
 
260
        }
 
261
 
 
262
        return NT_STATUS_OK;
 
263
}
 
264
 
 
265
/*******************************************************************
 
266
 Store a DATA_BLOB into a tdb record given an fsp pointer.
 
267
*******************************************************************/
 
268
 
 
269
static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
 
270
                                files_struct *fsp,
 
271
                                DATA_BLOB *pblob)
 
272
{
 
273
        uint8 id_buf[16];
 
274
        struct file_id id;
 
275
        SMB_STRUCT_STAT sbuf;
 
276
        TDB_DATA data;
 
277
        struct db_context *db;
 
278
        struct db_record *rec;
 
279
        int ret = -1;
 
280
 
 
281
        DEBUG(10,("store_acl_blob_fsp: storing blob length %u on file %s\n",
 
282
                        (unsigned int)pblob->length, fsp->fsp_name));
 
283
 
 
284
        SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
 
285
                return NT_STATUS_INTERNAL_DB_CORRUPTION);
 
286
 
 
287
        if (fsp->fh->fd != -1) {
 
288
                ret = SMB_VFS_FSTAT(fsp, &sbuf);
 
289
        } else {
 
290
                if (fsp->posix_open) {
 
291
                        ret = SMB_VFS_LSTAT(handle->conn, fsp->fsp_name, &sbuf);
 
292
                } else {
 
293
                        ret = SMB_VFS_STAT(handle->conn, fsp->fsp_name, &sbuf);
 
294
                }
 
295
        }
 
296
 
 
297
        if (ret == -1) {
 
298
                return map_nt_error_from_unix(errno);
 
299
        }
 
300
 
 
301
        id = vfs_file_id_from_sbuf(handle->conn, &sbuf);
 
302
 
 
303
        /* For backwards compatibility only store the dev/inode. */
 
304
        push_file_id_16((char *)id_buf, &id);
 
305
        rec = db->fetch_locked(db, talloc_tos(),
 
306
                                make_tdb_data(id_buf,
 
307
                                        sizeof(id_buf)));
 
308
        if (rec == NULL) {
 
309
                DEBUG(0, ("store_acl_blob_fsp_tdb: fetch_lock failed\n"));
 
310
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
311
        }
 
312
        data.dptr = pblob->data;
 
313
        data.dsize = pblob->length;
 
314
        return rec->store(rec, data, 0);
 
315
}
 
316
 
 
317
/*******************************************************************
 
318
 Store a DATA_BLOB into a tdb record given a pathname.
 
319
*******************************************************************/
 
320
 
 
321
static NTSTATUS store_acl_blob_pathname(vfs_handle_struct *handle,
 
322
                                        const char *fname,
 
323
                                        DATA_BLOB *pblob)
 
324
{
 
325
        uint8 id_buf[16];
 
326
        struct file_id id;
 
327
        TDB_DATA data;
 
328
        SMB_STRUCT_STAT sbuf;
 
329
        struct db_context *db;
 
330
        struct db_record *rec;
 
331
        int ret = -1;
 
332
 
 
333
        DEBUG(10,("store_acl_blob_pathname: storing blob "
 
334
                        "length %u on file %s\n",
 
335
                        (unsigned int)pblob->length, fname));
 
336
 
 
337
        SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
 
338
                return NT_STATUS_INTERNAL_DB_CORRUPTION);
 
339
 
 
340
        if (lp_posix_pathnames()) {
 
341
                ret = SMB_VFS_LSTAT(handle->conn, fname, &sbuf);
 
342
        } else {
 
343
                ret = SMB_VFS_STAT(handle->conn, fname, &sbuf);
 
344
        }
 
345
 
 
346
        if (ret == -1) {
 
347
                return map_nt_error_from_unix(errno);
 
348
        }
 
349
 
 
350
        id = vfs_file_id_from_sbuf(handle->conn, &sbuf);
 
351
 
 
352
        /* For backwards compatibility only store the dev/inode. */
 
353
        push_file_id_16((char *)id_buf, &id);
 
354
 
 
355
        rec = db->fetch_locked(db, talloc_tos(),
 
356
                                make_tdb_data(id_buf,
 
357
                                        sizeof(id_buf)));
 
358
        if (rec == NULL) {
 
359
                DEBUG(0, ("store_acl_blob_pathname_tdb: fetch_lock failed\n"));
 
360
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
361
        }
 
362
        data.dptr = pblob->data;
 
363
        data.dsize = pblob->length;
 
364
        return rec->store(rec, data, 0);
 
365
}
 
366
 
 
367
/*******************************************************************
 
368
 Store a DATA_BLOB into an tdb given a pathname.
 
369
*******************************************************************/
 
370
 
 
371
static NTSTATUS get_nt_acl_tdb_internal(vfs_handle_struct *handle,
 
372
                                        files_struct *fsp,
 
373
                                        const char *name,
 
374
                                        uint32 security_info,
 
375
                                        struct security_descriptor **ppdesc)
 
376
{
 
377
        TALLOC_CTX *ctx = talloc_tos();
 
378
        DATA_BLOB blob;
 
379
        NTSTATUS status;
 
380
 
 
381
        if (fsp && name == NULL) {
 
382
                name = fsp->fsp_name;
 
383
        }
 
384
 
 
385
        DEBUG(10, ("get_nt_acl_tdb_internal: name=%s\n", name));
 
386
 
 
387
        status = get_acl_blob(ctx, handle, fsp, name, &blob);
 
388
        if (!NT_STATUS_IS_OK(status)) {
 
389
                DEBUG(10, ("get_acl_blob returned %s\n", nt_errstr(status)));
 
390
                return status;
 
391
        }
 
392
 
 
393
        status = parse_acl_blob(&blob, security_info, ppdesc);
 
394
        if (!NT_STATUS_IS_OK(status)) {
 
395
                DEBUG(10, ("parse_acl_blob returned %s\n",
 
396
                                nt_errstr(status)));
 
397
                return status;
 
398
        }
 
399
 
 
400
        TALLOC_FREE(blob.data);
 
401
        return status;
 
402
}
 
403
 
 
404
/*********************************************************************
 
405
 Create a default security descriptor for a file in case no inheritance
 
406
 exists. All permissions to the owner and SYSTEM.
 
407
*********************************************************************/
 
408
 
 
409
static struct security_descriptor *default_file_sd(TALLOC_CTX *mem_ctx,
 
410
                                                SMB_STRUCT_STAT *psbuf)
 
411
{
 
412
        struct dom_sid owner_sid, group_sid;
 
413
        size_t sd_size;
 
414
        struct security_ace *pace = NULL;
 
415
        struct security_acl *pacl = NULL;
 
416
 
 
417
        uid_to_sid(&owner_sid, psbuf->st_uid);
 
418
        gid_to_sid(&group_sid, psbuf->st_gid);
 
419
 
 
420
        pace = TALLOC_ARRAY(mem_ctx, struct security_ace, 2);
 
421
        if (!pace) {
 
422
                return NULL;
 
423
        }
 
424
 
 
425
        init_sec_ace(&pace[0], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
 
426
                        SEC_RIGHTS_FILE_ALL, 0);
 
427
        init_sec_ace(&pace[1], &global_sid_System, SEC_ACE_TYPE_ACCESS_ALLOWED,
 
428
                        SEC_RIGHTS_FILE_ALL, 0);
 
429
 
 
430
        pacl = make_sec_acl(mem_ctx,
 
431
                                NT4_ACL_REVISION,
 
432
                                2,
 
433
                                pace);
 
434
        if (!pacl) {
 
435
                return NULL;
 
436
        }
 
437
        return make_sec_desc(mem_ctx,
 
438
                        SECURITY_DESCRIPTOR_REVISION_1,
 
439
                        SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
 
440
                        &owner_sid,
 
441
                        &group_sid,
 
442
                        NULL,
 
443
                        pacl,
 
444
                        &sd_size);
 
445
}
 
446
 
 
447
/*********************************************************************
 
448
*********************************************************************/
 
449
 
 
450
static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
 
451
                                        const char *fname,
 
452
                                        files_struct *fsp,
 
453
                                        bool container)
 
454
{
 
455
        TALLOC_CTX *ctx = talloc_tos();
 
456
        NTSTATUS status;
 
457
        struct security_descriptor *parent_desc = NULL;
 
458
        struct security_descriptor *psd = NULL;
 
459
        DATA_BLOB blob;
 
460
        size_t size;
 
461
        char *parent_name;
 
462
 
 
463
        if (!parent_dirname(ctx, fname, &parent_name, NULL)) {
 
464
                return NT_STATUS_NO_MEMORY;
 
465
        }
 
466
 
 
467
        DEBUG(10,("inherit_new_acl: check directory %s\n",
 
468
                        parent_name));
 
469
 
 
470
        status = get_nt_acl_tdb_internal(handle,
 
471
                                        NULL,
 
472
                                        parent_name,
 
473
                                        (OWNER_SECURITY_INFORMATION |
 
474
                                         GROUP_SECURITY_INFORMATION |
 
475
                                         DACL_SECURITY_INFORMATION),
 
476
                                        &parent_desc);
 
477
        if (NT_STATUS_IS_OK(status)) {
 
478
                /* Create an inherited descriptor from the parent. */
 
479
 
 
480
                if (DEBUGLEVEL >= 10) {
 
481
                        DEBUG(10,("inherit_new_acl: parent acl is:\n"));
 
482
                        NDR_PRINT_DEBUG(security_descriptor, parent_desc);
 
483
                }
 
484
 
 
485
                status = se_create_child_secdesc(ctx,
 
486
                                &psd,
 
487
                                &size,
 
488
                                parent_desc,
 
489
                                &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX],
 
490
                                &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX],
 
491
                                container);
 
492
                if (!NT_STATUS_IS_OK(status)) {
 
493
                        return status;
 
494
                }
 
495
 
 
496
                if (DEBUGLEVEL >= 10) {
 
497
                        DEBUG(10,("inherit_new_acl: child acl is:\n"));
 
498
                        NDR_PRINT_DEBUG(security_descriptor, psd);
 
499
                }
 
500
 
 
501
        } else {
 
502
                DEBUG(10,("inherit_new_acl: directory %s failed "
 
503
                        "to get acl %s\n",
 
504
                        parent_name,
 
505
                        nt_errstr(status) ));
 
506
        }
 
507
 
 
508
        if (!psd || psd->dacl == NULL) {
 
509
                SMB_STRUCT_STAT sbuf;
 
510
                int ret;
 
511
 
 
512
                TALLOC_FREE(psd);
 
513
                if (fsp && !fsp->is_directory && fsp->fh->fd != -1) {
 
514
                        ret = SMB_VFS_FSTAT(fsp, &sbuf);
 
515
                } else {
 
516
                        if (fsp && fsp->posix_open) {
 
517
                                ret = SMB_VFS_LSTAT(handle->conn,fname, &sbuf);
 
518
                        } else {
 
519
                                ret = SMB_VFS_STAT(handle->conn,fname, &sbuf);
 
520
                        }
 
521
                }
 
522
                if (ret == -1) {
 
523
                        return map_nt_error_from_unix(errno);
 
524
                }
 
525
                psd = default_file_sd(ctx, &sbuf);
 
526
                if (!psd) {
 
527
                        return NT_STATUS_NO_MEMORY;
 
528
                }
 
529
 
 
530
                if (DEBUGLEVEL >= 10) {
 
531
                        DEBUG(10,("inherit_new_acl: default acl is:\n"));
 
532
                        NDR_PRINT_DEBUG(security_descriptor, psd);
 
533
                }
 
534
        }
 
535
 
 
536
        status = create_acl_blob(psd, &blob);
 
537
        if (!NT_STATUS_IS_OK(status)) {
 
538
                return status;
 
539
        }
 
540
        if (fsp) {
 
541
                return store_acl_blob_fsp(handle, fsp, &blob);
 
542
        } else {
 
543
                return store_acl_blob_pathname(handle, fname, &blob);
 
544
        }
 
545
}
 
546
 
 
547
/*********************************************************************
 
548
 Check ACL on open. For new files inherit from parent directory.
 
549
*********************************************************************/
 
550
 
 
551
static int open_acl_tdb(vfs_handle_struct *handle,
 
552
                                        const char *fname,
 
553
                                        files_struct *fsp,
 
554
                                        int flags,
 
555
                                        mode_t mode)
 
556
{
 
557
        uint32_t access_granted = 0;
 
558
        struct security_descriptor *pdesc = NULL;
 
559
        bool file_existed = true;
 
560
        NTSTATUS status = get_nt_acl_tdb_internal(handle,
 
561
                                        NULL,
 
562
                                        fname,
 
563
                                        (OWNER_SECURITY_INFORMATION |
 
564
                                         GROUP_SECURITY_INFORMATION |
 
565
                                         DACL_SECURITY_INFORMATION),
 
566
                                        &pdesc);
 
567
        if (NT_STATUS_IS_OK(status)) {
 
568
                /* See if we can access it. */
 
569
                status = smb1_file_se_access_check(pdesc,
 
570
                                        handle->conn->server_info->ptok,
 
571
                                        fsp->access_mask,
 
572
                                        &access_granted);
 
573
                if (!NT_STATUS_IS_OK(status)) {
 
574
                        DEBUG(10,("open_acl_tdb: file %s open "
 
575
                                "refused with error %s\n",
 
576
                                fname,
 
577
                                nt_errstr(status) ));
 
578
                        errno = map_errno_from_nt_status(status);
 
579
                        return -1;
 
580
                }
 
581
        } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
 
582
                file_existed = false;
 
583
        }
 
584
 
 
585
        DEBUG(10,("open_acl_tdb: get_nt_acl_attr_internal for "
 
586
                "file %s returned %s\n",
 
587
                fname,
 
588
                nt_errstr(status) ));
 
589
 
 
590
        fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
 
591
 
 
592
        if (!file_existed && fsp->fh->fd != -1) {
 
593
                /* File was created. Inherit from parent directory. */
 
594
                string_set(&fsp->fsp_name, fname);
 
595
                inherit_new_acl(handle, fname, fsp, false);
 
596
        }
 
597
 
 
598
        return fsp->fh->fd;
 
599
}
 
600
 
 
601
/*********************************************************************
 
602
 On unlink we need to delete the tdb record (if using tdb).
 
603
*********************************************************************/
 
604
 
 
605
static int unlink_acl_tdb(vfs_handle_struct *handle, const char *path)
 
606
{
 
607
        SMB_STRUCT_STAT sbuf;
 
608
        struct db_context *db;
 
609
        int ret = -1;
 
610
 
 
611
        SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
 
612
 
 
613
        if (lp_posix_pathnames()) {
 
614
                ret = SMB_VFS_LSTAT(handle->conn, path, &sbuf);
 
615
        } else {
 
616
                ret = SMB_VFS_STAT(handle->conn, path, &sbuf);
 
617
        }
 
618
 
 
619
        if (ret == -1) {
 
620
                return -1;
 
621
        }
 
622
 
 
623
        ret = SMB_VFS_NEXT_UNLINK(handle, path);
 
624
 
 
625
        if (ret == -1) {
 
626
                return -1;
 
627
        }
 
628
 
 
629
        acl_tdb_delete(handle, db, &sbuf);
 
630
        return 0;
 
631
}
 
632
 
 
633
/*********************************************************************
 
634
 Store an inherited SD on mkdir.
 
635
*********************************************************************/
 
636
 
 
637
static int mkdir_acl_tdb(vfs_handle_struct *handle, const char *path, mode_t mode)
 
638
{
 
639
        int ret = SMB_VFS_NEXT_MKDIR(handle, path, mode);
 
640
 
 
641
        if (ret == -1) {
 
642
                return ret;
 
643
        }
 
644
        /* New directory - inherit from parent. */
 
645
        inherit_new_acl(handle, path, NULL, true);
 
646
        return ret;
 
647
}
 
648
 
 
649
/*********************************************************************
 
650
 On rmdir we need to delete the tdb record (if using tdb).
 
651
*********************************************************************/
 
652
 
 
653
static int rmdir_acl_tdb(vfs_handle_struct *handle, const char *path)
 
654
{
 
655
 
 
656
        SMB_STRUCT_STAT sbuf;
 
657
        struct db_context *db;
 
658
        int ret = -1;
 
659
 
 
660
        SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
 
661
 
 
662
        if (lp_posix_pathnames()) {
 
663
                ret = SMB_VFS_LSTAT(handle->conn, path, &sbuf);
 
664
        } else {
 
665
                ret = SMB_VFS_STAT(handle->conn, path, &sbuf);
 
666
        }
 
667
 
 
668
        if (ret == -1) {
 
669
                return -1;
 
670
        }
 
671
 
 
672
        ret = SMB_VFS_NEXT_RMDIR(handle, path);
 
673
        if (ret == -1) {
 
674
                return -1;
 
675
        }
 
676
 
 
677
        acl_tdb_delete(handle, db, &sbuf);
 
678
        return 0;
 
679
}
 
680
 
 
681
/*********************************************************************
 
682
 Fetch a security descriptor given an fsp.
 
683
*********************************************************************/
 
684
 
 
685
static NTSTATUS fget_nt_acl_tdb(vfs_handle_struct *handle, files_struct *fsp,
 
686
        uint32 security_info, struct security_descriptor **ppdesc)
 
687
{
 
688
        NTSTATUS status = get_nt_acl_tdb_internal(handle, fsp,
 
689
                                NULL, security_info, ppdesc);
 
690
        if (NT_STATUS_IS_OK(status)) {
 
691
                if (DEBUGLEVEL >= 10) {
 
692
                        DEBUG(10,("fget_nt_acl_tdb: returning tdb sd for file %s\n",
 
693
                                fsp->fsp_name));
 
694
                        NDR_PRINT_DEBUG(security_descriptor, *ppdesc);
 
695
                }
 
696
                return NT_STATUS_OK;
 
697
        }
 
698
 
 
699
        DEBUG(10,("fget_nt_acl_tdb: failed to get tdb sd for file %s, Error %s\n",
 
700
                        fsp->fsp_name,
 
701
                        nt_errstr(status) ));
 
702
 
 
703
        return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp,
 
704
                        security_info, ppdesc);
 
705
}
 
706
 
 
707
/*********************************************************************
 
708
 Fetch a security descriptor given a pathname.
 
709
*********************************************************************/
 
710
 
 
711
static NTSTATUS get_nt_acl_tdb(vfs_handle_struct *handle,
 
712
        const char *name, uint32 security_info, struct security_descriptor **ppdesc)
 
713
{
 
714
        NTSTATUS status = get_nt_acl_tdb_internal(handle, NULL,
 
715
                                name, security_info, ppdesc);
 
716
        if (NT_STATUS_IS_OK(status)) {
 
717
                if (DEBUGLEVEL >= 10) {
 
718
                        DEBUG(10,("get_nt_acl_tdb: returning tdb sd for file %s\n",
 
719
                                name));
 
720
                        NDR_PRINT_DEBUG(security_descriptor, *ppdesc);
 
721
                }
 
722
                return NT_STATUS_OK;
 
723
        }
 
724
 
 
725
        DEBUG(10,("get_nt_acl_tdb: failed to get tdb sd for file %s, Error %s\n",
 
726
                        name,
 
727
                        nt_errstr(status) ));
 
728
 
 
729
        return SMB_VFS_NEXT_GET_NT_ACL(handle, name,
 
730
                        security_info, ppdesc);
 
731
}
 
732
 
 
733
/*********************************************************************
 
734
 Store a security descriptor given an fsp.
 
735
*********************************************************************/
 
736
 
 
737
static NTSTATUS fset_nt_acl_tdb(vfs_handle_struct *handle, files_struct *fsp,
 
738
        uint32 security_info_sent, const struct security_descriptor *psd)
 
739
{
 
740
        NTSTATUS status;
 
741
        DATA_BLOB blob;
 
742
 
 
743
        if (DEBUGLEVEL >= 10) {
 
744
                DEBUG(10,("fset_nt_acl_tdb: incoming sd for file %s\n",
 
745
                        fsp->fsp_name));
 
746
                NDR_PRINT_DEBUG(security_descriptor,
 
747
                        CONST_DISCARD(struct security_descriptor *,psd));
 
748
        }
 
749
 
 
750
        status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
 
751
        if (!NT_STATUS_IS_OK(status)) {
 
752
                return status;
 
753
        }
 
754
 
 
755
        /* Ensure owner and group are set. */
 
756
        if (!psd->owner_sid || !psd->group_sid) {
 
757
                int ret;
 
758
                SMB_STRUCT_STAT sbuf;
 
759
                DOM_SID owner_sid, group_sid;
 
760
                struct security_descriptor *nc_psd = dup_sec_desc(talloc_tos(), psd);
 
761
 
 
762
                if (!nc_psd) {
 
763
                        return NT_STATUS_OK;
 
764
                }
 
765
                if (fsp->is_directory || fsp->fh->fd == -1) {
 
766
                        if (fsp->posix_open) {
 
767
                                ret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name, &sbuf);
 
768
                        } else {
 
769
                                ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf);
 
770
                        }
 
771
                } else {
 
772
                        ret = SMB_VFS_FSTAT(fsp, &sbuf);
 
773
                }
 
774
                if (ret == -1) {
 
775
                        /* Lower level acl set succeeded,
 
776
                         * so still return OK. */
 
777
                        return NT_STATUS_OK;
 
778
                }
 
779
                create_file_sids(&sbuf, &owner_sid, &group_sid);
 
780
                /* This is safe as nc_psd is discarded at fn exit. */
 
781
                nc_psd->owner_sid = &owner_sid;
 
782
                nc_psd->group_sid = &group_sid;
 
783
                security_info_sent |= (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION);
 
784
                psd = nc_psd;
 
785
        }
 
786
 
 
787
#if 0
 
788
        if ((security_info_sent & DACL_SECURITY_INFORMATION) &&
 
789
                        psd->dacl != NULL &&
 
790
                        (psd->type & (SE_DESC_DACL_AUTO_INHERITED|
 
791
                                SE_DESC_DACL_AUTO_INHERIT_REQ))==
 
792
                                (SE_DESC_DACL_AUTO_INHERITED|
 
793
                                SE_DESC_DACL_AUTO_INHERIT_REQ) ) {
 
794
                struct security_descriptor *new_psd = NULL;
 
795
                status = append_parent_acl(fsp, psd, &new_psd);
 
796
                if (!NT_STATUS_IS_OK(status)) {
 
797
                        /* Lower level acl set succeeded,
 
798
                         * so still return OK. */
 
799
                        return NT_STATUS_OK;
 
800
                }
 
801
                psd = new_psd;
 
802
        }
 
803
#endif
 
804
 
 
805
        if (DEBUGLEVEL >= 10) {
 
806
                DEBUG(10,("fset_nt_acl_tdb: storing tdb sd for file %s\n",
 
807
                        fsp->fsp_name));
 
808
                NDR_PRINT_DEBUG(security_descriptor,
 
809
                        CONST_DISCARD(struct security_descriptor *,psd));
 
810
        }
 
811
        create_acl_blob(psd, &blob);
 
812
        store_acl_blob_fsp(handle, fsp, &blob);
 
813
 
 
814
        return NT_STATUS_OK;
 
815
}
 
816
 
 
817
/*******************************************************************
 
818
 Handle opening the storage tdb if so configured.
 
819
*******************************************************************/
 
820
 
 
821
static int connect_acl_tdb(struct vfs_handle_struct *handle,
 
822
                                const char *service,
 
823
                                const char *user)
 
824
{
 
825
        struct db_context *db;
 
826
        int res;
 
827
 
 
828
        res = SMB_VFS_NEXT_CONNECT(handle, service, user);
 
829
        if (res < 0) {
 
830
                return res;
 
831
        }
 
832
 
 
833
        if (!acl_tdb_init(&db)) {
 
834
                SMB_VFS_NEXT_DISCONNECT(handle);
 
835
                return -1;
 
836
        }
 
837
 
 
838
        SMB_VFS_HANDLE_SET_DATA(handle, db, free_acl_tdb_data,
 
839
                                struct db_context, return -1);
 
840
 
 
841
        return 0;
 
842
}
 
843
 
 
844
/*********************************************************************
 
845
 Remove a Windows ACL - we're setting the underlying POSIX ACL.
 
846
*********************************************************************/
 
847
 
 
848
static int sys_acl_set_file_tdb(vfs_handle_struct *handle,
 
849
                              const char *path,
 
850
                              SMB_ACL_TYPE_T type,
 
851
                              SMB_ACL_T theacl)
 
852
{
 
853
        SMB_STRUCT_STAT sbuf;
 
854
        struct db_context *db;
 
855
        int ret = -1;
 
856
 
 
857
        SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
 
858
 
 
859
        if (lp_posix_pathnames()) {
 
860
                ret = SMB_VFS_LSTAT(handle->conn, path, &sbuf);
 
861
        } else {
 
862
                ret = SMB_VFS_STAT(handle->conn, path, &sbuf);
 
863
        }
 
864
 
 
865
        if (ret == -1) {
 
866
                return -1;
 
867
        }
 
868
 
 
869
        ret = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle,
 
870
                                                path,
 
871
                                                type,
 
872
                                                theacl);
 
873
        if (ret == -1) {
 
874
                return -1;
 
875
        }
 
876
 
 
877
        acl_tdb_delete(handle, db, &sbuf);
 
878
        return 0;
 
879
}
 
880
 
 
881
/*********************************************************************
 
882
 Remove a Windows ACL - we're setting the underlying POSIX ACL.
 
883
*********************************************************************/
 
884
 
 
885
static int sys_acl_set_fd_tdb(vfs_handle_struct *handle,
 
886
                            files_struct *fsp,
 
887
                            SMB_ACL_T theacl)
 
888
{
 
889
        SMB_STRUCT_STAT sbuf;
 
890
        struct db_context *db;
 
891
        int ret;
 
892
 
 
893
        SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
 
894
 
 
895
        if (fsp->is_directory || fsp->fh->fd == -1) {
 
896
                if (fsp->posix_open) {
 
897
                        ret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name, &sbuf);
 
898
                } else {
 
899
                        ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf);
 
900
                }
 
901
        } else {
 
902
                ret = SMB_VFS_FSTAT(fsp, &sbuf);
 
903
        }
 
904
        if (ret == -1) {
 
905
                return -1;
 
906
        }
 
907
 
 
908
        ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle,
 
909
                                                fsp,
 
910
                                                theacl);
 
911
        if (ret == -1) {
 
912
                return -1;
 
913
        }
 
914
 
 
915
        acl_tdb_delete(handle, db, &sbuf);
 
916
        return 0;
 
917
}
 
918
 
 
919
/* VFS operations structure */
 
920
 
 
921
static vfs_op_tuple skel_op_tuples[] =
 
922
{
 
923
        {SMB_VFS_OP(connect_acl_tdb), SMB_VFS_OP_CONNECT,  SMB_VFS_LAYER_TRANSPARENT},
 
924
 
 
925
        {SMB_VFS_OP(mkdir_acl_tdb), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_TRANSPARENT},
 
926
        {SMB_VFS_OP(rmdir_acl_tdb), SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_TRANSPARENT},
 
927
 
 
928
        {SMB_VFS_OP(open_acl_tdb),  SMB_VFS_OP_OPEN,  SMB_VFS_LAYER_TRANSPARENT},
 
929
        {SMB_VFS_OP(unlink_acl_tdb), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_TRANSPARENT},
 
930
 
 
931
        /* NT File ACL operations */
 
932
 
 
933
        {SMB_VFS_OP(fget_nt_acl_tdb),SMB_VFS_OP_FGET_NT_ACL,SMB_VFS_LAYER_TRANSPARENT},
 
934
        {SMB_VFS_OP(get_nt_acl_tdb), SMB_VFS_OP_GET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT},
 
935
        {SMB_VFS_OP(fset_nt_acl_tdb),SMB_VFS_OP_FSET_NT_ACL,SMB_VFS_LAYER_TRANSPARENT},
 
936
 
 
937
        /* POSIX ACL operations. */
 
938
        {SMB_VFS_OP(sys_acl_set_file_tdb), SMB_VFS_OP_SYS_ACL_SET_FILE, SMB_VFS_LAYER_TRANSPARENT},
 
939
        {SMB_VFS_OP(sys_acl_set_fd_tdb), SMB_VFS_OP_SYS_ACL_SET_FD, SMB_VFS_LAYER_TRANSPARENT},
 
940
 
 
941
        {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
 
942
};
 
943
 
 
944
NTSTATUS vfs_acl_tdb_init(void)
 
945
{
 
946
        return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "acl_tdb", skel_op_tuples);
 
947
}