Make acl_tdb match acl_xattr. Large duplication of
[ira/wip.git] / source3 / modules / vfs_acl_tdb.c
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 #include "../lib/crypto/crypto.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_VFS
30
31 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
32                         DATA_BLOB *pblob,
33                         uint16_t hash_type,
34                         uint8_t hash[XATTR_SD_HASH_SIZE]);
35
36 #define HASH_SECURITY_INFO (OWNER_SECURITY_INFORMATION | \
37                                 GROUP_SECURITY_INFORMATION | \
38                                 DACL_SECURITY_INFORMATION | \
39                                 SACL_SECURITY_INFORMATION)
40
41 static unsigned int ref_count;
42 static struct db_context *acl_db;
43
44 /*******************************************************************
45  Open acl_db if not already open, increment ref count.
46 *******************************************************************/
47
48 static bool acl_tdb_init(struct db_context **pp_db)
49 {
50         char *dbname;
51
52         if (acl_db) {
53                 *pp_db = acl_db;
54                 ref_count++;
55                 return true;
56         }
57
58         dbname = state_path("file_ntacls.tdb");
59
60         if (dbname == NULL) {
61                 errno = ENOSYS;
62                 return false;
63         }
64
65         become_root();
66         *pp_db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
67         unbecome_root();
68
69         if (*pp_db == NULL) {
70 #if defined(ENOTSUP)
71                 errno = ENOTSUP;
72 #else
73                 errno = ENOSYS;
74 #endif
75                 TALLOC_FREE(dbname);
76                 return false;
77         }
78
79         ref_count++;
80         TALLOC_FREE(dbname);
81         return true;
82 }
83
84 /*******************************************************************
85  Lower ref count and close acl_db if zero.
86 *******************************************************************/
87
88 static void free_acl_tdb_data(void **pptr)
89 {
90         struct db_context **pp_db = (struct db_context **)pptr;
91
92         ref_count--;
93         if (ref_count == 0) {
94                 TALLOC_FREE(*pp_db);
95                 acl_db = NULL;
96         }
97 }
98
99 /*******************************************************************
100  Fetch_lock the tdb acl record for a file
101 *******************************************************************/
102
103 static struct db_record *acl_tdb_lock(TALLOC_CTX *mem_ctx,
104                                         struct db_context *db,
105                                         const struct file_id *id)
106 {
107         uint8 id_buf[16];
108
109         /* For backwards compatibility only store the dev/inode. */
110         push_file_id_16((char *)id_buf, id);
111         return db->fetch_locked(db,
112                                 mem_ctx,
113                                 make_tdb_data(id_buf,
114                                         sizeof(id_buf)));
115 }
116
117 /*******************************************************************
118  Delete the tdb acl record for a file
119 *******************************************************************/
120
121 static NTSTATUS acl_tdb_delete(vfs_handle_struct *handle,
122                                 struct db_context *db,
123                                 SMB_STRUCT_STAT *psbuf)
124 {
125         NTSTATUS status;
126         struct file_id id = vfs_file_id_from_sbuf(handle->conn, psbuf);
127         struct db_record *rec = acl_tdb_lock(talloc_tos(), db, &id);
128
129         /*
130          * If rec == NULL there's not much we can do about it
131          */
132
133         if (rec == NULL) {
134                 DEBUG(10,("acl_tdb_delete: rec == NULL\n"));
135                 TALLOC_FREE(rec);
136                 return NT_STATUS_OK;
137         }
138
139         status = rec->delete_rec(rec);
140         TALLOC_FREE(rec);
141         return status;
142 }
143
144 /*******************************************************************
145  Hash a security descriptor.
146 *******************************************************************/
147
148 static NTSTATUS hash_sd_sha256(struct security_descriptor *psd,
149                         uint8_t hash[XATTR_SD_HASH_SIZE])
150 {
151         DATA_BLOB blob;
152         SHA256_CTX tctx;
153         NTSTATUS status;
154
155         memset(hash, '\0', XATTR_SD_HASH_SIZE);
156         status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
157         if (!NT_STATUS_IS_OK(status)) {
158                 return status;
159         }
160
161         SHA256_Init(&tctx);
162         SHA256_Update(&tctx, blob.data, blob.length);
163         SHA256_Final(hash, &tctx);
164
165         return NT_STATUS_OK;
166 }
167
168 /*******************************************************************
169  Parse out a struct security_descriptor from a DATA_BLOB.
170 *******************************************************************/
171
172 static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
173                                 struct security_descriptor **ppdesc,
174                                 uint16_t *p_hash_type,
175                                 uint8_t hash[XATTR_SD_HASH_SIZE])
176 {
177         TALLOC_CTX *ctx = talloc_tos();
178         struct xattr_NTACL xacl;
179         enum ndr_err_code ndr_err;
180         size_t sd_size;
181
182         ndr_err = ndr_pull_struct_blob(pblob, ctx, NULL, &xacl,
183                         (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
184
185         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
186                 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
187                         ndr_errstr(ndr_err)));
188                 return ndr_map_error2ntstatus(ndr_err);;
189         }
190
191         switch (xacl.version) {
192                 case 2:
193                         *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION,
194                                         xacl.info.sd_hs2->sd->type | SEC_DESC_SELF_RELATIVE,
195                                         xacl.info.sd_hs2->sd->owner_sid,
196                                         xacl.info.sd_hs2->sd->group_sid,
197                                         xacl.info.sd_hs2->sd->sacl,
198                                         xacl.info.sd_hs2->sd->dacl,
199                                         &sd_size);
200                         /* No hash - null out. */
201                         *p_hash_type = XATTR_SD_HASH_TYPE_NONE;
202                         memset(hash, '\0', XATTR_SD_HASH_SIZE);
203                         break;
204                 case 3:
205                         *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION,
206                                         xacl.info.sd_hs3->sd->type | SEC_DESC_SELF_RELATIVE,
207                                         xacl.info.sd_hs3->sd->owner_sid,
208                                         xacl.info.sd_hs3->sd->group_sid,
209                                         xacl.info.sd_hs3->sd->sacl,
210                                         xacl.info.sd_hs3->sd->dacl,
211                                         &sd_size);
212                         *p_hash_type = xacl.info.sd_hs3->hash_type;
213                         /* Current version 3. */
214                         memcpy(hash, xacl.info.sd_hs3->hash, XATTR_SD_HASH_SIZE);
215                         break;
216                 default:
217                         return NT_STATUS_REVISION_MISMATCH;
218         }
219
220         TALLOC_FREE(xacl.info.sd);
221
222         return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
223 }
224
225 /*******************************************************************
226  Pull a security descriptor into a DATA_BLOB from a tdb store.
227 *******************************************************************/
228
229 static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
230                         vfs_handle_struct *handle,
231                         files_struct *fsp,
232                         const char *name,
233                         DATA_BLOB *pblob)
234 {
235         uint8 id_buf[16];
236         TDB_DATA data;
237         struct file_id id;
238         struct db_context *db;
239         int ret = -1;
240         SMB_STRUCT_STAT sbuf;
241
242         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
243                 return NT_STATUS_INTERNAL_DB_CORRUPTION);
244
245         if (fsp && fsp->fh->fd != -1) {
246                 ret = SMB_VFS_FSTAT(fsp, &sbuf);
247         } else {
248                 if (fsp && fsp->posix_open) {
249                         ret = vfs_lstat_smb_fname(handle->conn, name, &sbuf);
250                 } else {
251                         ret = vfs_stat_smb_fname(handle->conn, name, &sbuf);
252                 }
253         }
254
255         if (ret == -1) {
256                 return map_nt_error_from_unix(errno);
257         }
258
259         id = vfs_file_id_from_sbuf(handle->conn, &sbuf);
260
261         /* For backwards compatibility only store the dev/inode. */
262         push_file_id_16((char *)id_buf, &id);
263
264         if (db->fetch(db,
265                         ctx,
266                         make_tdb_data(id_buf, sizeof(id_buf)),
267                         &data) == -1) {
268                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
269         }
270
271         pblob->data = data.dptr;
272         pblob->length = data.dsize;
273
274         DEBUG(10,("get_acl_blob: returned %u bytes from file %s\n",
275                 (unsigned int)data.dsize, name ));
276
277         if (pblob->length == 0 || pblob->data == NULL) {
278                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
279         }
280         return NT_STATUS_OK;
281 }
282
283 /*******************************************************************
284  Create a DATA_BLOB from a security descriptor.
285 *******************************************************************/
286
287 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
288                         DATA_BLOB *pblob,
289                         uint16_t hash_type,
290                         uint8_t hash[XATTR_SD_HASH_SIZE])
291 {
292         struct xattr_NTACL xacl;
293         struct security_descriptor_hash_v3 sd_hs3;
294         enum ndr_err_code ndr_err;
295         TALLOC_CTX *ctx = talloc_tos();
296
297         ZERO_STRUCT(xacl);
298         ZERO_STRUCT(sd_hs3);
299
300         xacl.version = 3;
301         xacl.info.sd_hs3 = &sd_hs3;
302         xacl.info.sd_hs3->sd = CONST_DISCARD(struct security_descriptor *, psd);
303         xacl.info.sd_hs3->hash_type = hash_type;
304         memcpy(&xacl.info.sd_hs3->hash[0], hash, XATTR_SD_HASH_SIZE);
305
306         ndr_err = ndr_push_struct_blob(
307                         pblob, ctx, NULL, &xacl,
308                         (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
309
310         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
311                 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
312                         ndr_errstr(ndr_err)));
313                 return ndr_map_error2ntstatus(ndr_err);;
314         }
315
316         return NT_STATUS_OK;
317 }
318
319 /*******************************************************************
320  Store a DATA_BLOB into a tdb record given an fsp pointer.
321 *******************************************************************/
322
323 static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
324                                 files_struct *fsp,
325                                 DATA_BLOB *pblob)
326 {
327         uint8 id_buf[16];
328         struct file_id id;
329         TDB_DATA data;
330         struct db_context *db;
331         struct db_record *rec;
332         int ret = -1;
333
334         DEBUG(10,("store_acl_blob_fsp: storing blob length %u on file %s\n",
335                   (unsigned int)pblob->length, fsp_str_dbg(fsp)));
336
337         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
338                 return NT_STATUS_INTERNAL_DB_CORRUPTION);
339
340         if (fsp->fh->fd != -1) {
341                 ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
342         } else {
343                 if (fsp->posix_open) {
344                         ret = SMB_VFS_LSTAT(handle->conn, fsp->fsp_name);
345                 } else {
346                         ret = SMB_VFS_STAT(handle->conn, fsp->fsp_name);
347                 }
348         }
349
350         if (ret == -1) {
351                 return map_nt_error_from_unix(errno);
352         }
353
354         id = vfs_file_id_from_sbuf(handle->conn, &fsp->fsp_name->st);
355
356         /* For backwards compatibility only store the dev/inode. */
357         push_file_id_16((char *)id_buf, &id);
358         rec = db->fetch_locked(db, talloc_tos(),
359                                 make_tdb_data(id_buf,
360                                         sizeof(id_buf)));
361         if (rec == NULL) {
362                 DEBUG(0, ("store_acl_blob_fsp_tdb: fetch_lock failed\n"));
363                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
364         }
365         data.dptr = pblob->data;
366         data.dsize = pblob->length;
367         return rec->store(rec, data, 0);
368 }
369
370 /*******************************************************************
371  Store a DATA_BLOB into a tdb record given a pathname.
372 *******************************************************************/
373
374 static NTSTATUS store_acl_blob_pathname(vfs_handle_struct *handle,
375                                         const char *fname,
376                                         DATA_BLOB *pblob)
377 {
378         uint8 id_buf[16];
379         struct file_id id;
380         TDB_DATA data;
381         SMB_STRUCT_STAT sbuf;
382         struct db_context *db;
383         struct db_record *rec;
384         int ret = -1;
385
386         DEBUG(10,("store_acl_blob_pathname: storing blob "
387                         "length %u on file %s\n",
388                         (unsigned int)pblob->length, fname));
389
390         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
391                 return NT_STATUS_INTERNAL_DB_CORRUPTION);
392
393         if (lp_posix_pathnames()) {
394                 ret = vfs_lstat_smb_fname(handle->conn, fname, &sbuf);
395         } else {
396                 ret = vfs_stat_smb_fname(handle->conn, fname, &sbuf);
397         }
398
399         if (ret == -1) {
400                 return map_nt_error_from_unix(errno);
401         }
402
403         id = vfs_file_id_from_sbuf(handle->conn, &sbuf);
404
405         /* For backwards compatibility only store the dev/inode. */
406         push_file_id_16((char *)id_buf, &id);
407
408         rec = db->fetch_locked(db, talloc_tos(),
409                                 make_tdb_data(id_buf,
410                                         sizeof(id_buf)));
411         if (rec == NULL) {
412                 DEBUG(0, ("store_acl_blob_pathname_tdb: fetch_lock failed\n"));
413                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
414         }
415         data.dptr = pblob->data;
416         data.dsize = pblob->length;
417         return rec->store(rec, data, 0);
418 }
419
420 /*******************************************************************
421  Store a DATA_BLOB into an tdb given a pathname.
422 *******************************************************************/
423
424 static NTSTATUS get_nt_acl_tdb_internal(vfs_handle_struct *handle,
425                                         files_struct *fsp,
426                                         const char *name,
427                                         uint32_t security_info,
428                                         struct security_descriptor **ppdesc)
429 {
430         DATA_BLOB blob;
431         NTSTATUS status;
432         uint16_t hash_type;
433         uint8_t hash[XATTR_SD_HASH_SIZE];
434         uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
435         struct security_descriptor *pdesc_next = NULL;
436
437         if (fsp && name == NULL) {
438                 name = fsp->fsp_name->base_name;
439         }
440
441         DEBUG(10, ("get_nt_acl_tdb_internal: name=%s\n", name));
442
443         status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
444         if (!NT_STATUS_IS_OK(status)) {
445                 DEBUG(10, ("get_acl_blob returned %s\n", nt_errstr(status)));
446                 return status;
447         }
448
449         status = parse_acl_blob(&blob, ppdesc,
450                                 &hash_type, &hash[0]);
451         if (!NT_STATUS_IS_OK(status)) {
452                 DEBUG(10, ("parse_acl_blob returned %s\n",
453                         nt_errstr(status)));
454                 return status;
455         }
456
457         /* Ensure the hash type is one we know. */
458         switch (hash_type) {
459                 case XATTR_SD_HASH_TYPE_NONE:
460                         /* No hash, goto return blob sd. */
461                         goto out;
462                 case XATTR_SD_HASH_TYPE_SHA256:
463                         break;
464                 default:
465                         return NT_STATUS_REVISION_MISMATCH;
466         }
467
468         /* Get the full underlying sd, then hash. */
469         if (fsp) {
470                 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
471                                 fsp,
472                                 HASH_SECURITY_INFO,
473                                 &pdesc_next);
474         } else {
475                 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
476                                 name,
477                                 HASH_SECURITY_INFO,
478                                 &pdesc_next);
479         }
480
481         if (!NT_STATUS_IS_OK(status)) {
482                 goto out;
483         }
484
485         status = hash_sd_sha256(pdesc_next, hash_tmp);
486         if (!NT_STATUS_IS_OK(status)) {
487                 goto out;
488         }
489
490         if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
491                 TALLOC_FREE(pdesc_next);
492                 /* Hash matches, return blob sd. */
493                 goto out;
494         }
495
496         /* Hash doesn't match, return underlying sd. */
497
498         if (!(security_info & OWNER_SECURITY_INFORMATION)) {
499                 pdesc_next->owner_sid = NULL;
500         }
501         if (!(security_info & GROUP_SECURITY_INFORMATION)) {
502                 pdesc_next->group_sid = NULL;
503         }
504         if (!(security_info & DACL_SECURITY_INFORMATION)) {
505                 pdesc_next->dacl = NULL;
506         }
507         if (!(security_info & SACL_SECURITY_INFORMATION)) {
508                 pdesc_next->sacl = NULL;
509         }
510
511         TALLOC_FREE(*ppdesc);
512         *ppdesc = pdesc_next;
513
514   out:
515
516         if (!(security_info & OWNER_SECURITY_INFORMATION)) {
517                 (*ppdesc)->owner_sid = NULL;
518         }
519         if (!(security_info & GROUP_SECURITY_INFORMATION)) {
520                 (*ppdesc)->group_sid = NULL;
521         }
522         if (!(security_info & DACL_SECURITY_INFORMATION)) {
523                 (*ppdesc)->dacl = NULL;
524         }
525         if (!(security_info & SACL_SECURITY_INFORMATION)) {
526                 (*ppdesc)->sacl = NULL;
527         }
528
529         TALLOC_FREE(blob.data);
530         return status;
531 }
532
533 /*********************************************************************
534  Create a default security descriptor for a file in case no inheritance
535  exists. All permissions to the owner and SYSTEM.
536 *********************************************************************/
537
538 static struct security_descriptor *default_file_sd(TALLOC_CTX *mem_ctx,
539                                                 SMB_STRUCT_STAT *psbuf)
540 {
541         struct dom_sid owner_sid, group_sid;
542         size_t sd_size;
543         struct security_ace *pace = NULL;
544         struct security_acl *pacl = NULL;
545
546         uid_to_sid(&owner_sid, psbuf->st_ex_uid);
547         gid_to_sid(&group_sid, psbuf->st_ex_gid);
548
549         pace = TALLOC_ARRAY(mem_ctx, struct security_ace, 2);
550         if (!pace) {
551                 return NULL;
552         }
553
554         init_sec_ace(&pace[0], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
555                         SEC_RIGHTS_FILE_ALL, 0);
556         init_sec_ace(&pace[1], &global_sid_System, SEC_ACE_TYPE_ACCESS_ALLOWED,
557                         SEC_RIGHTS_FILE_ALL, 0);
558
559         pacl = make_sec_acl(mem_ctx,
560                                 NT4_ACL_REVISION,
561                                 2,
562                                 pace);
563         if (!pacl) {
564                 return NULL;
565         }
566         return make_sec_desc(mem_ctx,
567                         SECURITY_DESCRIPTOR_REVISION_1,
568                         SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
569                         &owner_sid,
570                         &group_sid,
571                         NULL,
572                         pacl,
573                         &sd_size);
574 }
575
576 /*********************************************************************
577 *********************************************************************/
578
579 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
580                                         struct smb_filename *smb_fname,
581                                         files_struct *fsp,
582                                         bool container)
583 {
584         TALLOC_CTX *ctx = talloc_tos();
585         NTSTATUS status;
586         struct security_descriptor *parent_desc = NULL;
587         struct security_descriptor *psd = NULL;
588         struct security_descriptor *pdesc_next = NULL;
589         DATA_BLOB blob;
590         size_t size;
591         char *parent_name;
592         uint8_t hash[XATTR_SD_HASH_SIZE];
593
594         if (!parent_dirname(ctx, smb_fname->base_name, &parent_name, NULL)) {
595                 return NT_STATUS_NO_MEMORY;
596         }
597
598         DEBUG(10,("inherit_new_acl: check directory %s\n",
599                         parent_name));
600
601         status = get_nt_acl_tdb_internal(handle,
602                                         NULL,
603                                         parent_name,
604                                         (OWNER_SECURITY_INFORMATION |
605                                          GROUP_SECURITY_INFORMATION |
606                                          DACL_SECURITY_INFORMATION),
607                                         &parent_desc);
608         if (NT_STATUS_IS_OK(status)) {
609                 /* Create an inherited descriptor from the parent. */
610
611                 if (DEBUGLEVEL >= 10) {
612                         DEBUG(10,("inherit_new_acl: parent acl is:\n"));
613                         NDR_PRINT_DEBUG(security_descriptor, parent_desc);
614                 }
615
616                 status = se_create_child_secdesc(ctx,
617                                 &psd,
618                                 &size,
619                                 parent_desc,
620                                 &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX],
621                                 &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX],
622                                 container);
623                 if (!NT_STATUS_IS_OK(status)) {
624                         return status;
625                 }
626
627                 if (DEBUGLEVEL >= 10) {
628                         DEBUG(10,("inherit_new_acl: child acl is:\n"));
629                         NDR_PRINT_DEBUG(security_descriptor, psd);
630                 }
631
632         } else {
633                 DEBUG(10,("inherit_new_acl: directory %s failed "
634                         "to get acl %s\n",
635                         parent_name,
636                         nt_errstr(status) ));
637         }
638
639         if (!psd || psd->dacl == NULL) {
640                 int ret;
641
642                 TALLOC_FREE(psd);
643                 if (fsp && !fsp->is_directory && fsp->fh->fd != -1) {
644                         ret = SMB_VFS_FSTAT(fsp, &smb_fname->st);
645                 } else {
646                         if (fsp && fsp->posix_open) {
647                                 ret = SMB_VFS_LSTAT(handle->conn, smb_fname);
648                         } else {
649                                 ret = SMB_VFS_STAT(handle->conn, smb_fname);
650                         }
651                 }
652                 if (ret == -1) {
653                         return map_nt_error_from_unix(errno);
654                 }
655                 psd = default_file_sd(ctx, &smb_fname->st);
656                 if (!psd) {
657                         return NT_STATUS_NO_MEMORY;
658                 }
659
660                 if (DEBUGLEVEL >= 10) {
661                         DEBUG(10,("inherit_new_acl: default acl is:\n"));
662                         NDR_PRINT_DEBUG(security_descriptor, psd);
663                 }
664         }
665
666         /* Object exists. Read the current SD to get the hash. */
667         if (fsp) {
668                 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
669                                 fsp,
670                                 HASH_SECURITY_INFO,
671                                 &pdesc_next);
672         } else {
673                 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
674                                 smb_fname->base_name,
675                                 HASH_SECURITY_INFO,
676                                 &pdesc_next);
677         }
678
679         if (!NT_STATUS_IS_OK(status)) {
680                 return status;
681         }
682
683         status = hash_sd_sha256(pdesc_next, hash);
684         if (!NT_STATUS_IS_OK(status)) {
685                 return status;
686         }
687         status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
688         if (!NT_STATUS_IS_OK(status)) {
689                 return status;
690         }
691         if (fsp) {
692                 return store_acl_blob_fsp(handle, fsp, &blob);
693         } else {
694                 return store_acl_blob_pathname(handle, smb_fname->base_name,
695                                                &blob);
696         }
697 }
698
699 /*********************************************************************
700  Check ACL on open. For new files inherit from parent directory.
701 *********************************************************************/
702
703 static int open_acl_tdb(vfs_handle_struct *handle,
704                                         struct smb_filename *smb_fname,
705                                         files_struct *fsp,
706                                         int flags,
707                                         mode_t mode)
708 {
709         uint32_t access_granted = 0;
710         struct security_descriptor *pdesc = NULL;
711         bool file_existed = true;
712         char *fname = NULL;
713         NTSTATUS status;
714
715         if (fsp->base_fsp) {
716                 /* Stream open. Base filename open already did the ACL check. */
717                 DEBUG(10,("open_acl_tdb: stream open on %s\n",
718                         smb_fname_str_dbg(smb_fname) ));
719                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
720         }
721
722         status = get_full_smb_filename(talloc_tos(), smb_fname,
723                                        &fname);
724         if (!NT_STATUS_IS_OK(status)) {
725                 errno = map_errno_from_nt_status(status);
726                 return -1;
727         }
728
729         status = get_nt_acl_tdb_internal(handle,
730                                         NULL,
731                                         fname,
732                                         (OWNER_SECURITY_INFORMATION |
733                                          GROUP_SECURITY_INFORMATION |
734                                          DACL_SECURITY_INFORMATION),
735                                         &pdesc);
736         if (NT_STATUS_IS_OK(status)) {
737                 /* See if we can access it. */
738                 status = smb1_file_se_access_check(pdesc,
739                                         handle->conn->server_info->ptok,
740                                         fsp->access_mask,
741                                         &access_granted);
742                 if (!NT_STATUS_IS_OK(status)) {
743                         DEBUG(10,("open_acl_tdb: file %s open "
744                                 "refused with error %s\n",
745                                 smb_fname_str_dbg(smb_fname),
746                                 nt_errstr(status) ));
747                         errno = map_errno_from_nt_status(status);
748                         return -1;
749                 }
750         } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
751                 file_existed = false;
752         }
753
754         DEBUG(10,("open_acl_tdb: get_nt_acl_attr_internal for "
755                 "file %s returned %s\n",
756                 smb_fname_str_dbg(smb_fname),
757                 nt_errstr(status) ));
758
759         fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
760
761         if (!file_existed && fsp->fh->fd != -1) {
762                 /* File was created. Inherit from parent directory. */
763                 status = fsp_set_smb_fname(fsp, smb_fname);
764                 if (!NT_STATUS_IS_OK(status)) {
765                         errno = map_errno_from_nt_status(status);
766                         return -1;
767                 }
768                 inherit_new_acl(handle, smb_fname, fsp, false);
769         }
770
771         return fsp->fh->fd;
772 }
773
774 /*********************************************************************
775  On unlink we need to delete the tdb record (if using tdb).
776 *********************************************************************/
777
778 static int unlink_acl_tdb(vfs_handle_struct *handle,
779                           const struct smb_filename *smb_fname)
780 {
781         struct smb_filename *smb_fname_tmp = NULL;
782         struct db_context *db;
783         NTSTATUS status;
784         int ret = -1;
785
786         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
787
788         status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
789         if (!NT_STATUS_IS_OK(status)) {
790                 errno = map_errno_from_nt_status(status);
791                 goto out;
792         }
793
794         if (lp_posix_pathnames()) {
795                 ret = SMB_VFS_LSTAT(handle->conn, smb_fname_tmp);
796         } else {
797                 ret = SMB_VFS_STAT(handle->conn, smb_fname_tmp);
798         }
799
800         if (ret == -1) {
801                 goto out;
802         }
803
804         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
805
806         if (ret == -1) {
807                 goto out;
808         }
809
810         acl_tdb_delete(handle, db, &smb_fname_tmp->st);
811  out:
812         return ret;
813 }
814
815 /*********************************************************************
816  Store an inherited SD on mkdir.
817 *********************************************************************/
818
819 static int mkdir_acl_tdb(vfs_handle_struct *handle, const char *path, mode_t mode)
820 {
821         struct smb_filename *smb_fname = NULL;
822         int ret = SMB_VFS_NEXT_MKDIR(handle, path, mode);
823         NTSTATUS status;
824
825         if (ret == -1) {
826                 return ret;
827         }
828
829         status = create_synthetic_smb_fname(talloc_tos(), path, NULL, NULL,
830                                             &smb_fname);
831         if (!NT_STATUS_IS_OK(status)) {
832                 errno = map_errno_from_nt_status(status);
833                 return -1;
834         }
835
836         /* New directory - inherit from parent. */
837         inherit_new_acl(handle, smb_fname, NULL, true);
838         TALLOC_FREE(smb_fname);
839         return ret;
840 }
841
842 /*********************************************************************
843  On rmdir we need to delete the tdb record (if using tdb).
844 *********************************************************************/
845
846 static int rmdir_acl_tdb(vfs_handle_struct *handle, const char *path)
847 {
848
849         SMB_STRUCT_STAT sbuf;
850         struct db_context *db;
851         int ret = -1;
852
853         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
854
855         if (lp_posix_pathnames()) {
856                 ret = vfs_lstat_smb_fname(handle->conn, path, &sbuf);
857         } else {
858                 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
859         }
860
861         if (ret == -1) {
862                 return -1;
863         }
864
865         ret = SMB_VFS_NEXT_RMDIR(handle, path);
866         if (ret == -1) {
867                 return -1;
868         }
869
870         acl_tdb_delete(handle, db, &sbuf);
871         return 0;
872 }
873
874 /*********************************************************************
875  Fetch a security descriptor given an fsp.
876 *********************************************************************/
877
878 static NTSTATUS fget_nt_acl_tdb(vfs_handle_struct *handle, files_struct *fsp,
879         uint32 security_info, struct security_descriptor **ppdesc)
880 {
881         return get_nt_acl_tdb_internal(handle, fsp,
882                                 NULL, security_info, ppdesc);
883 }
884
885 /*********************************************************************
886  Fetch a security descriptor given a pathname.
887 *********************************************************************/
888
889 static NTSTATUS get_nt_acl_tdb(vfs_handle_struct *handle,
890         const char *name, uint32 security_info, struct security_descriptor **ppdesc)
891 {
892         return get_nt_acl_tdb_internal(handle, NULL,
893                                 name, security_info, ppdesc);
894 }
895
896 /*********************************************************************
897  Store a security descriptor given an fsp.
898 *********************************************************************/
899
900 static NTSTATUS fset_nt_acl_tdb(vfs_handle_struct *handle, files_struct *fsp,
901         uint32_t security_info_sent, const struct security_descriptor *psd)
902 {
903         NTSTATUS status;
904         DATA_BLOB blob;
905         struct security_descriptor *pdesc_next = NULL;
906         uint8_t hash[XATTR_SD_HASH_SIZE];
907
908         if (DEBUGLEVEL >= 10) {
909                 DEBUG(10,("fset_nt_acl_tdb: incoming sd for file %s\n",
910                           fsp_str_dbg(fsp)));
911                 NDR_PRINT_DEBUG(security_descriptor,
912                         CONST_DISCARD(struct security_descriptor *,psd));
913         }
914
915         /* Ensure owner and group are set. */
916         if (!psd->owner_sid || !psd->group_sid) {
917                 int ret;
918                 DOM_SID owner_sid, group_sid;
919                 struct security_descriptor *nc_psd = dup_sec_desc(talloc_tos(), psd);
920
921                 if (!nc_psd) {
922                         return NT_STATUS_OK;
923                 }
924                 if (fsp->is_directory || fsp->fh->fd == -1) {
925                         if (fsp->posix_open) {
926                                 ret = SMB_VFS_LSTAT(fsp->conn, fsp->fsp_name);
927                         } else {
928                                 ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name);
929                         }
930                 } else {
931                         ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
932                 }
933                 if (ret == -1) {
934                         /* Lower level acl set succeeded,
935                          * so still return OK. */
936                         return NT_STATUS_OK;
937                 }
938                 create_file_sids(&fsp->fsp_name->st, &owner_sid, &group_sid);
939                 /* This is safe as nc_psd is discarded at fn exit. */
940                 nc_psd->owner_sid = &owner_sid;
941                 nc_psd->group_sid = &group_sid;
942                 security_info_sent |= (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION);
943                 psd = nc_psd;
944         }
945
946         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
947         if (!NT_STATUS_IS_OK(status)) {
948                 return status;
949         }
950
951         /* Get the full underlying sd, then hash. */
952         status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
953                                 fsp,
954                                 HASH_SECURITY_INFO,
955                                 &pdesc_next);
956
957         if (!NT_STATUS_IS_OK(status)) {
958                 return status;
959         }
960
961         status = hash_sd_sha256(pdesc_next, hash);
962         if (!NT_STATUS_IS_OK(status)) {
963                 return status;
964         }
965
966 #if 0
967         if ((security_info_sent & DACL_SECURITY_INFORMATION) &&
968                         psd->dacl != NULL &&
969                         (psd->type & (SE_DESC_DACL_AUTO_INHERITED|
970                                 SE_DESC_DACL_AUTO_INHERIT_REQ))==
971                                 (SE_DESC_DACL_AUTO_INHERITED|
972                                 SE_DESC_DACL_AUTO_INHERIT_REQ) ) {
973                 struct security_descriptor *new_psd = NULL;
974                 status = append_parent_acl(fsp, psd, &new_psd);
975                 if (!NT_STATUS_IS_OK(status)) {
976                         /* Lower level acl set succeeded,
977                          * so still return OK. */
978                         return NT_STATUS_OK;
979                 }
980                 psd = new_psd;
981         }
982 #endif
983
984         if (DEBUGLEVEL >= 10) {
985                 DEBUG(10,("fset_nt_acl_tdb: storing xattr sd for file %s\n",
986                           fsp_str_dbg(fsp)));
987                 NDR_PRINT_DEBUG(security_descriptor,
988                         CONST_DISCARD(struct security_descriptor *,psd));
989         }
990         create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
991         store_acl_blob_fsp(handle, fsp, &blob);
992
993         return NT_STATUS_OK;
994 }
995
996 /*******************************************************************
997  Handle opening the storage tdb if so configured.
998 *******************************************************************/
999
1000 static int connect_acl_tdb(struct vfs_handle_struct *handle,
1001                                 const char *service,
1002                                 const char *user)
1003 {
1004         struct db_context *db;
1005         int res;
1006
1007         res = SMB_VFS_NEXT_CONNECT(handle, service, user);
1008         if (res < 0) {
1009                 return res;
1010         }
1011
1012         if (!acl_tdb_init(&db)) {
1013                 SMB_VFS_NEXT_DISCONNECT(handle);
1014                 return -1;
1015         }
1016
1017         SMB_VFS_HANDLE_SET_DATA(handle, db, free_acl_tdb_data,
1018                                 struct db_context, return -1);
1019
1020         return 0;
1021 }
1022
1023 /*********************************************************************
1024  Remove a Windows ACL - we're setting the underlying POSIX ACL.
1025 *********************************************************************/
1026
1027 static int sys_acl_set_file_tdb(vfs_handle_struct *handle,
1028                               const char *path,
1029                               SMB_ACL_TYPE_T type,
1030                               SMB_ACL_T theacl)
1031 {
1032         SMB_STRUCT_STAT sbuf;
1033         struct db_context *db;
1034         int ret = -1;
1035
1036         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
1037
1038         if (lp_posix_pathnames()) {
1039                 ret = vfs_lstat_smb_fname(handle->conn, path, &sbuf);
1040         } else {
1041                 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
1042         }
1043
1044         if (ret == -1) {
1045                 return -1;
1046         }
1047
1048         ret = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle,
1049                                                 path,
1050                                                 type,
1051                                                 theacl);
1052         if (ret == -1) {
1053                 return -1;
1054         }
1055
1056         acl_tdb_delete(handle, db, &sbuf);
1057         return 0;
1058 }
1059
1060 /*********************************************************************
1061  Remove a Windows ACL - we're setting the underlying POSIX ACL.
1062 *********************************************************************/
1063
1064 static int sys_acl_set_fd_tdb(vfs_handle_struct *handle,
1065                             files_struct *fsp,
1066                             SMB_ACL_T theacl)
1067 {
1068         struct db_context *db;
1069         int ret;
1070
1071         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
1072
1073         if (fsp->is_directory || fsp->fh->fd == -1) {
1074                 if (fsp->posix_open) {
1075                         ret = SMB_VFS_LSTAT(fsp->conn, fsp->fsp_name);
1076                 } else {
1077                         ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name);
1078                 }
1079         } else {
1080                 ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
1081         }
1082         if (ret == -1) {
1083                 return -1;
1084         }
1085
1086         ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle,
1087                                                 fsp,
1088                                                 theacl);
1089         if (ret == -1) {
1090                 return -1;
1091         }
1092
1093         acl_tdb_delete(handle, db, &fsp->fsp_name->st);
1094         return 0;
1095 }
1096
1097 static struct vfs_fn_pointers vfs_acl_tdb_fns = {
1098         .connect_fn = connect_acl_tdb,
1099         .mkdir = mkdir_acl_tdb,
1100         .open = open_acl_tdb,
1101         .unlink = unlink_acl_tdb,
1102         .rmdir = rmdir_acl_tdb,
1103         .fget_nt_acl = fget_nt_acl_tdb,
1104         .get_nt_acl = get_nt_acl_tdb,
1105         .fset_nt_acl = fset_nt_acl_tdb,
1106         .sys_acl_set_file = sys_acl_set_file_tdb,
1107         .sys_acl_set_fd = sys_acl_set_fd_tdb
1108 };
1109
1110 NTSTATUS vfs_acl_tdb_init(void)
1111 {
1112         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "acl_tdb",
1113                                 &vfs_acl_tdb_fns);
1114 }