Move v2 from timestamp to 16-byte hash. Got the change in before on disk format is...
[samba.git] / source3 / modules / vfs_acl_tdb.c
1 /*
2  * Store Windows ACLs in xattrs, or a tdb if configured that way.
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         const char *dbname;
40
41         if (acl_db) {
42                 *pp_db = acl_db;
43                 ref_count++;
44                 return true;
45         }
46
47         dbname = lock_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                 return false;
65         }
66
67         ref_count++;
68         return true;
69 }
70
71 /*******************************************************************
72  Lower ref count and close acl_db if zero.
73 *******************************************************************/
74
75 static void free_acl_xattr_data(void **pptr)
76 {
77         struct db_context **pp_db = (struct db_context **)pptr;
78
79         ref_count--;
80         if (ref_count == 0) {
81                 TALLOC_FREE(*pp_db);
82                 acl_db = NULL;
83         }
84 }
85
86 /*******************************************************************
87  Fetch_lock the tdb acl record for a file
88 *******************************************************************/
89
90 static struct db_record *acl_xattr_tdb_lock(TALLOC_CTX *mem_ctx,
91                                         struct db_context *db,
92                                         const struct file_id *id)
93 {
94         uint8 id_buf[16];
95         push_file_id_16((char *)id_buf, id);
96         return db->fetch_locked(db,
97                                 mem_ctx,
98                                 make_tdb_data(id_buf,
99                                         sizeof(id_buf)));
100 }
101
102 /*******************************************************************
103  Parse out a struct security_descriptor from a DATA_BLOB.
104 *******************************************************************/
105
106 static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
107                                 uint32 security_info,
108                                 struct security_descriptor **ppdesc)
109 {
110         TALLOC_CTX *ctx = talloc_tos();
111         struct xattr_NTACL xacl;
112         enum ndr_err_code ndr_err;
113         size_t sd_size;
114
115         ndr_err = ndr_pull_struct_blob(pblob, ctx, NULL, &xacl,
116                         (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
117
118         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
119                 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
120                         ndr_errstr(ndr_err)));
121                 return ndr_map_error2ntstatus(ndr_err);;
122         }
123
124         if (xacl.version != 2) {
125                 return NT_STATUS_REVISION_MISMATCH;
126         }
127
128         *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION, xacl.info.sd_hs->sd->type | SEC_DESC_SELF_RELATIVE,
129                         (security_info & OWNER_SECURITY_INFORMATION)
130                         ? xacl.info.sd_hs->sd->owner_sid : NULL,
131                         (security_info & GROUP_SECURITY_INFORMATION)
132                         ? xacl.info.sd_hs->sd->group_sid : NULL,
133                         (security_info & SACL_SECURITY_INFORMATION)
134                         ? xacl.info.sd_hs->sd->sacl : NULL,
135                         (security_info & DACL_SECURITY_INFORMATION)
136                         ? xacl.info.sd_hs->sd->dacl : NULL,
137                         &sd_size);
138
139         TALLOC_FREE(xacl.info.sd);
140
141         return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
142 }
143
144 /*******************************************************************
145  Pull a security descriptor into a DATA_BLOB from a tdb store.
146 *******************************************************************/
147
148 static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
149                         vfs_handle_struct *handle,
150                         files_struct *fsp,
151                         const char *name,
152                         DATA_BLOB *pblob)
153 {
154         uint8 id_buf[16];
155         TDB_DATA data;
156         struct file_id id;
157         struct db_context *db;
158         SMB_STRUCT_STAT sbuf;
159
160         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
161                 return NT_STATUS_INTERNAL_DB_CORRUPTION);
162
163         if (fsp && fsp->fh->fd != -1) {
164                 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
165                         return map_nt_error_from_unix(errno);
166                 }
167         } else {
168                 if (SMB_VFS_STAT(handle->conn, name, &sbuf) == -1) {
169                         return map_nt_error_from_unix(errno);
170                 }
171         }
172         id = vfs_file_id_from_sbuf(handle->conn, &sbuf);
173
174         push_file_id_16((char *)id_buf, &id);
175
176         if (db->fetch(db,
177                         ctx,
178                         make_tdb_data(id_buf, sizeof(id_buf)),
179                         &data) == -1) {
180                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
181         }
182
183         pblob->data = data.dptr;
184         pblob->length = data.dsize;
185
186         DEBUG(10,("get_acl_blob: returned %u bytes from file %s\n",
187                 (unsigned int)data.dsize, name ));
188
189         if (pblob->length == 0 || pblob->data == NULL) {
190                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
191         }
192         return NT_STATUS_OK;
193 }
194
195 /*******************************************************************
196  Create a DATA_BLOB from a security descriptor.
197 *******************************************************************/
198
199 static NTSTATUS create_acl_blob(const struct security_descriptor *psd, DATA_BLOB *pblob)
200 {
201         struct xattr_NTACL xacl;
202         struct security_descriptor_hash sd_hs;
203         enum ndr_err_code ndr_err;
204         TALLOC_CTX *ctx = talloc_tos();
205
206         ZERO_STRUCT(xacl);
207         ZERO_STRUCT(sd_hs);
208
209         xacl.version = 2;
210         xacl.info.sd_hs = &sd_hs;
211         xacl.info.sd_hs->sd = CONST_DISCARD(struct security_descriptor *, psd);
212         memset(&xacl.info.sd_hs->hash[0], '\0', 16);
213
214         ndr_err = ndr_push_struct_blob(
215                         pblob, ctx, NULL, &xacl,
216                         (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
217
218         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
219                 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
220                         ndr_errstr(ndr_err)));
221                 return ndr_map_error2ntstatus(ndr_err);;
222         }
223
224         return NT_STATUS_OK;
225 }
226
227 /*******************************************************************
228  Store a DATA_BLOB into a tdb record given an fsp pointer.
229 *******************************************************************/
230
231 static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
232                                 files_struct *fsp,
233                                 DATA_BLOB *pblob)
234 {
235         uint8 id_buf[16];
236         struct file_id id;
237         SMB_STRUCT_STAT sbuf;
238         TDB_DATA data;
239         struct db_context *db;
240         struct db_record *rec;
241
242         DEBUG(10,("store_acl_blob_fsp: storing blob length %u on file %s\n",
243                         (unsigned int)pblob->length, fsp->fsp_name));
244
245         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
246                 return NT_STATUS_INTERNAL_DB_CORRUPTION);
247
248         if (fsp->fh->fd != -1) {
249                 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
250                         return map_nt_error_from_unix(errno);
251                 }
252         } else {
253                 if (SMB_VFS_STAT(handle->conn, fsp->fsp_name, &sbuf) == -1) {
254                         return map_nt_error_from_unix(errno);
255                 }
256         }
257         id = vfs_file_id_from_sbuf(handle->conn, &sbuf);
258
259         push_file_id_16((char *)id_buf, &id);
260         rec = db->fetch_locked(db, talloc_tos(),
261                                 make_tdb_data(id_buf,
262                                         sizeof(id_buf)));
263         if (rec == NULL) {
264                 DEBUG(0, ("store_acl_blob_fsp_tdb: fetch_lock failed\n"));
265                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
266         }
267         data.dptr = pblob->data;
268         data.dsize = pblob->length;
269         return rec->store(rec, data, 0);
270 }
271
272 /*******************************************************************
273  Store a DATA_BLOB into a tdb record given a pathname.
274 *******************************************************************/
275
276 static NTSTATUS store_acl_blob_pathname(vfs_handle_struct *handle,
277                                         const char *fname,
278                                         DATA_BLOB *pblob)
279 {
280         uint8 id_buf[16];
281         struct file_id id;
282         TDB_DATA data;
283         SMB_STRUCT_STAT sbuf;
284         struct db_context *db;
285         struct db_record *rec;
286
287         DEBUG(10,("store_acl_blob_pathname: storing blob "
288                         "length %u on file %s\n",
289                         (unsigned int)pblob->length, fname));
290
291         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
292                 return NT_STATUS_INTERNAL_DB_CORRUPTION);
293
294         if (SMB_VFS_STAT(handle->conn, fname, &sbuf) == -1) {
295                 return map_nt_error_from_unix(errno);
296         }
297
298         id = vfs_file_id_from_sbuf(handle->conn, &sbuf);
299         push_file_id_16((char *)id_buf, &id);
300
301         rec = db->fetch_locked(db, talloc_tos(),
302                                 make_tdb_data(id_buf,
303                                         sizeof(id_buf)));
304         if (rec == NULL) {
305                 DEBUG(0, ("store_acl_blob_pathname_tdb: fetch_lock failed\n"));
306                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
307         }
308         data.dptr = pblob->data;
309         data.dsize = pblob->length;
310         return rec->store(rec, data, 0);
311 }
312
313 /*******************************************************************
314  Store a DATA_BLOB into an xattr given a pathname.
315 *******************************************************************/
316
317 static NTSTATUS get_nt_acl_xattr_internal(vfs_handle_struct *handle,
318                                         files_struct *fsp,
319                                         const char *name,
320                                         uint32 security_info,
321                                         struct security_descriptor **ppdesc)
322 {
323         TALLOC_CTX *ctx = talloc_tos();
324         DATA_BLOB blob;
325         NTSTATUS status;
326
327         if (fsp && name == NULL) {
328                 name = fsp->fsp_name;
329         }
330
331         DEBUG(10, ("get_nt_acl_xattr_internal: name=%s\n", name));
332
333         status = get_acl_blob(ctx, handle, fsp, name, &blob);
334         if (!NT_STATUS_IS_OK(status)) {
335                 DEBUG(10, ("get_acl_blob returned %s\n", nt_errstr(status)));
336                 return status;
337         }
338
339         status = parse_acl_blob(&blob, security_info, ppdesc);
340         if (!NT_STATUS_IS_OK(status)) {
341                 DEBUG(10, ("parse_acl_blob returned %s\n",
342                                 nt_errstr(status)));
343                 return status;
344         }
345
346         TALLOC_FREE(blob.data);
347         return status;
348 }
349
350 /*********************************************************************
351  Create a default security descriptor for a file in case no inheritance
352  exists. All permissions to the owner and SYSTEM.
353 *********************************************************************/
354
355 static struct security_descriptor *default_file_sd(TALLOC_CTX *mem_ctx,
356                                                 SMB_STRUCT_STAT *psbuf)
357 {
358         struct dom_sid owner_sid, group_sid;
359         size_t sd_size;
360         struct security_ace *pace = NULL;
361         struct security_acl *pacl = NULL;
362
363         uid_to_sid(&owner_sid, psbuf->st_uid);
364         gid_to_sid(&group_sid, psbuf->st_gid);
365
366         pace = TALLOC_ARRAY(mem_ctx, struct security_ace, 2);
367         if (!pace) {
368                 return NULL;
369         }
370
371         init_sec_ace(&pace[0], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
372                         SEC_RIGHTS_FILE_ALL, 0);
373         init_sec_ace(&pace[1], &global_sid_System, SEC_ACE_TYPE_ACCESS_ALLOWED,
374                         SEC_RIGHTS_FILE_ALL, 0);
375
376         pacl = make_sec_acl(mem_ctx,
377                                 NT4_ACL_REVISION,
378                                 2,
379                                 pace);
380         if (!pacl) {
381                 return NULL;
382         }
383         return make_sec_desc(mem_ctx,
384                         SECURITY_DESCRIPTOR_REVISION_1,
385                         SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
386                         &owner_sid,
387                         &group_sid,
388                         NULL,
389                         pacl,
390                         &sd_size);
391 }
392
393 /*********************************************************************
394 *********************************************************************/
395
396 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
397                                         const char *fname,
398                                         files_struct *fsp,
399                                         bool container)
400 {
401         TALLOC_CTX *ctx = talloc_tos();
402         NTSTATUS status;
403         struct security_descriptor *parent_desc = NULL;
404         struct security_descriptor *psd = NULL;
405         DATA_BLOB blob;
406         size_t size;
407         char *parent_name;
408
409         if (!parent_dirname_talloc(ctx,
410                                 fname,
411                                 &parent_name,
412                                 NULL)) {
413                 return NT_STATUS_NO_MEMORY;
414         }
415
416         DEBUG(10,("inherit_new_acl: check directory %s\n",
417                         parent_name));
418
419         status = get_nt_acl_xattr_internal(handle,
420                                         NULL,
421                                         parent_name,
422                                         (OWNER_SECURITY_INFORMATION |
423                                          GROUP_SECURITY_INFORMATION |
424                                          DACL_SECURITY_INFORMATION),
425                                         &parent_desc);
426         if (NT_STATUS_IS_OK(status)) {
427                 /* Create an inherited descriptor from the parent. */
428
429                 if (DEBUGLEVEL >= 10) {
430                         DEBUG(10,("inherit_new_acl: parent acl is:\n"));
431                         NDR_PRINT_DEBUG(security_descriptor, parent_desc);
432                 }
433
434                 status = se_create_child_secdesc(ctx,
435                                 &psd,
436                                 &size,
437                                 parent_desc,
438                                 &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX],
439                                 &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX],
440                                 container);
441                 if (!NT_STATUS_IS_OK(status)) {
442                         return status;
443                 }
444
445                 if (DEBUGLEVEL >= 10) {
446                         DEBUG(10,("inherit_new_acl: child acl is:\n"));
447                         NDR_PRINT_DEBUG(security_descriptor, psd);
448                 }
449
450         } else {
451                 DEBUG(10,("inherit_new_acl: directory %s failed "
452                         "to get acl %s\n",
453                         parent_name,
454                         nt_errstr(status) ));
455         }
456
457         if (!psd || psd->dacl == NULL) {
458                 SMB_STRUCT_STAT sbuf;
459                 int ret;
460
461                 TALLOC_FREE(psd);
462                 if (fsp && !fsp->is_directory && fsp->fh->fd != -1) {
463                         ret = SMB_VFS_FSTAT(fsp, &sbuf);
464                 } else {
465                         ret = SMB_VFS_STAT(handle->conn,fname, &sbuf);
466                 }
467                 if (ret == -1) {
468                         return map_nt_error_from_unix(errno);
469                 }
470                 psd = default_file_sd(ctx, &sbuf);
471                 if (!psd) {
472                         return NT_STATUS_NO_MEMORY;
473                 }
474
475                 if (DEBUGLEVEL >= 10) {
476                         DEBUG(10,("inherit_new_acl: default acl is:\n"));
477                         NDR_PRINT_DEBUG(security_descriptor, psd);
478                 }
479         }
480
481         status = create_acl_blob(psd, &blob);
482         if (!NT_STATUS_IS_OK(status)) {
483                 return status;
484         }
485         if (fsp) {
486                 return store_acl_blob_fsp(handle, fsp, &blob);
487         } else {
488                 return store_acl_blob_pathname(handle, fname, &blob);
489         }
490 }
491
492 /*********************************************************************
493  Check ACL on open. For new files inherit from parent directory.
494 *********************************************************************/
495
496 static int open_acl_xattr(vfs_handle_struct *handle,
497                                         const char *fname,
498                                         files_struct *fsp,
499                                         int flags,
500                                         mode_t mode)
501 {
502         uint32_t access_granted = 0;
503         struct security_descriptor *pdesc = NULL;
504         bool file_existed = true;
505         NTSTATUS status = get_nt_acl_xattr_internal(handle,
506                                         NULL,
507                                         fname,
508                                         (OWNER_SECURITY_INFORMATION |
509                                          GROUP_SECURITY_INFORMATION |
510                                          DACL_SECURITY_INFORMATION),
511                                         &pdesc);
512         if (NT_STATUS_IS_OK(status)) {
513                 /* See if we can access it. */
514                 status = smb1_file_se_access_check(pdesc,
515                                         handle->conn->server_info->ptok,
516                                         fsp->access_mask,
517                                         &access_granted);
518                 if (!NT_STATUS_IS_OK(status)) {
519                         DEBUG(10,("open_acl_xattr: file %s open "
520                                 "refused with error %s\n",
521                                 fname,
522                                 nt_errstr(status) ));
523                         errno = map_errno_from_nt_status(status);
524                         return -1;
525                 }
526         } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
527                 file_existed = false;
528         }
529
530         DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
531                 "file %s returned %s\n",
532                 fname,
533                 nt_errstr(status) ));
534
535         fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
536
537         if (!file_existed && fsp->fh->fd != -1) {
538                 /* File was created. Inherit from parent directory. */
539                 string_set(&fsp->fsp_name, fname);
540                 inherit_new_acl(handle, fname, fsp, false);
541         }
542
543         return fsp->fh->fd;
544 }
545
546 /*********************************************************************
547  On unlink we need to delete the tdb record (if using tdb).
548 *********************************************************************/
549
550 static int unlink_acl_xattr(vfs_handle_struct *handle, const char *path)
551 {
552         SMB_STRUCT_STAT sbuf;
553         struct file_id id;
554         struct db_context *db;
555         struct db_record *rec;
556         int ret;
557
558         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
559
560         if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
561                 return -1;
562         }
563
564         ret = SMB_VFS_NEXT_UNLINK(handle, path);
565
566         if (ret == -1) {
567                 return -1;
568         }
569
570         id = vfs_file_id_from_sbuf(handle->conn, &sbuf);
571
572         rec = acl_xattr_tdb_lock(talloc_tos(), db, &id);
573
574         /*
575          * If rec == NULL there's not much we can do about it
576          */
577
578         if (rec == NULL) {
579                 DEBUG(10,("unlink_acl_xattr: path %s rec == NULL\n",
580                         path ));
581                 TALLOC_FREE(rec);
582                 return 0;
583         }
584
585         rec->delete_rec(rec);
586         TALLOC_FREE(rec);
587
588         return 0;
589 }
590
591 /*********************************************************************
592  Store an inherited SD on mkdir.
593 *********************************************************************/
594
595 static int mkdir_acl_xattr(vfs_handle_struct *handle, const char *path, mode_t mode)
596 {
597         int ret = SMB_VFS_NEXT_MKDIR(handle, path, mode);
598
599         if (ret == -1) {
600                 return ret;
601         }
602         /* New directory - inherit from parent. */
603         inherit_new_acl(handle, path, NULL, true);
604         return ret;
605 }
606
607 /*********************************************************************
608  On rmdir we need to delete the tdb record (if using tdb).
609 *********************************************************************/
610
611 static int rmdir_acl_xattr(vfs_handle_struct *handle, const char *path)
612 {
613         SMB_STRUCT_STAT sbuf;
614         struct file_id id;
615         struct db_context *db;
616         struct db_record *rec;
617         int ret;
618
619         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
620
621         if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
622                 return -1;
623         }
624
625         ret = SMB_VFS_NEXT_RMDIR(handle, path);
626
627         if (ret == -1) {
628                 return -1;
629         }
630
631         id = vfs_file_id_from_sbuf(handle->conn, &sbuf);
632
633         rec = acl_xattr_tdb_lock(talloc_tos(), db, &id);
634
635         /*
636          * If rec == NULL there's not much we can do about it
637          */
638
639         if (rec == NULL) {
640                 DEBUG(10,("rmdir_acl_xattr: path %s rec == NULL\n",
641                         path ));
642                 TALLOC_FREE(rec);
643                 return 0;
644         }
645
646         rec->delete_rec(rec);
647         TALLOC_FREE(rec);
648
649         return 0;
650 }
651
652 /*********************************************************************
653  Fetch a security descriptor given an fsp.
654 *********************************************************************/
655
656 static NTSTATUS fget_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp,
657         uint32 security_info, struct security_descriptor **ppdesc)
658 {
659         NTSTATUS status = get_nt_acl_xattr_internal(handle, fsp,
660                                 NULL, security_info, ppdesc);
661         if (NT_STATUS_IS_OK(status)) {
662                 if (DEBUGLEVEL >= 10) {
663                         DEBUG(10,("fget_nt_acl_xattr: returning xattr sd for file %s\n",
664                                 fsp->fsp_name));
665                         NDR_PRINT_DEBUG(security_descriptor, *ppdesc);
666                 }
667                 return NT_STATUS_OK;
668         }
669
670         DEBUG(10,("fget_nt_acl_xattr: failed to get xattr sd for file %s, Error %s\n",
671                         fsp->fsp_name,
672                         nt_errstr(status) ));
673
674         return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp,
675                         security_info, ppdesc);
676 }
677
678 /*********************************************************************
679  Fetch a security descriptor given a pathname.
680 *********************************************************************/
681
682 static NTSTATUS get_nt_acl_xattr(vfs_handle_struct *handle,
683         const char *name, uint32 security_info, struct security_descriptor **ppdesc)
684 {
685         NTSTATUS status = get_nt_acl_xattr_internal(handle, NULL,
686                                 name, security_info, ppdesc);
687         if (NT_STATUS_IS_OK(status)) {
688                 if (DEBUGLEVEL >= 10) {
689                         DEBUG(10,("get_nt_acl_xattr: returning xattr sd for file %s\n",
690                                 name));
691                         NDR_PRINT_DEBUG(security_descriptor, *ppdesc);
692                 }
693                 return NT_STATUS_OK;
694         }
695
696         DEBUG(10,("get_nt_acl_xattr: failed to get xattr sd for file %s, Error %s\n",
697                         name,
698                         nt_errstr(status) ));
699
700         return SMB_VFS_NEXT_GET_NT_ACL(handle, name,
701                         security_info, ppdesc);
702 }
703
704 /*********************************************************************
705  Store a security descriptor given an fsp.
706 *********************************************************************/
707
708 static NTSTATUS fset_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp,
709         uint32 security_info_sent, const struct security_descriptor *psd)
710 {
711         NTSTATUS status;
712         DATA_BLOB blob;
713
714         if (DEBUGLEVEL >= 10) {
715                 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
716                         fsp->fsp_name));
717                 NDR_PRINT_DEBUG(security_descriptor,
718                         CONST_DISCARD(struct security_descriptor *,psd));
719         }
720
721         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
722         if (!NT_STATUS_IS_OK(status)) {
723                 return status;
724         }
725
726         /* Ensure owner and group are set. */
727         if (!psd->owner_sid || !psd->group_sid) {
728                 int ret;
729                 SMB_STRUCT_STAT sbuf;
730                 DOM_SID owner_sid, group_sid;
731                 struct security_descriptor *nc_psd = dup_sec_desc(talloc_tos(), psd);
732
733                 if (!nc_psd) {
734                         return NT_STATUS_OK;
735                 }
736                 if (fsp->is_directory || fsp->fh->fd == -1) {
737                         ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf);
738                 } else {
739                         ret = SMB_VFS_FSTAT(fsp, &sbuf);
740                 }
741                 if (ret == -1) {
742                         /* Lower level acl set succeeded,
743                          * so still return OK. */
744                         return NT_STATUS_OK;
745                 }
746                 create_file_sids(&sbuf, &owner_sid, &group_sid);
747                 /* This is safe as nc_psd is discarded at fn exit. */
748                 nc_psd->owner_sid = &owner_sid;
749                 nc_psd->group_sid = &group_sid;
750                 security_info_sent |= (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION);
751                 psd = nc_psd;
752         }
753
754         if ((security_info_sent & DACL_SECURITY_INFORMATION) &&
755                         psd->dacl != NULL &&
756                         (psd->type & (SE_DESC_DACL_AUTO_INHERITED|
757                                 SE_DESC_DACL_AUTO_INHERIT_REQ))==
758                                 (SE_DESC_DACL_AUTO_INHERITED|
759                                 SE_DESC_DACL_AUTO_INHERIT_REQ) ) {
760                 struct security_descriptor *new_psd = NULL;
761                 status = append_parent_acl(fsp, psd, &new_psd);
762                 if (!NT_STATUS_IS_OK(status)) {
763                         /* Lower level acl set succeeded,
764                          * so still return OK. */
765                         return NT_STATUS_OK;
766                 }
767                 psd = new_psd;
768         }
769
770         if (DEBUGLEVEL >= 10) {
771                 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
772                         fsp->fsp_name));
773                 NDR_PRINT_DEBUG(security_descriptor,
774                         CONST_DISCARD(struct security_descriptor *,psd));
775         }
776         create_acl_blob(psd, &blob);
777         store_acl_blob_fsp(handle, fsp, &blob);
778
779         return NT_STATUS_OK;
780 }
781
782 /*******************************************************************
783  Handle opening the storage tdb if so configured.
784 *******************************************************************/
785
786 static int connect_acl_xattr(struct vfs_handle_struct *handle,
787                                 const char *service,
788                                 const char *user)
789 {
790         struct db_context *db;
791         int res;
792
793         res = SMB_VFS_NEXT_CONNECT(handle, service, user);
794         if (res < 0) {
795                 return res;
796         }
797
798         if (!acl_tdb_init(&db)) {
799                 SMB_VFS_NEXT_DISCONNECT(handle);
800                 return -1;
801         }
802
803         SMB_VFS_HANDLE_SET_DATA(handle, db, free_acl_xattr_data,
804                                 struct db_context, return -1);
805
806         return 0;
807 }
808
809 /* VFS operations structure */
810
811 static vfs_op_tuple skel_op_tuples[] =
812 {
813         {SMB_VFS_OP(connect_acl_xattr), SMB_VFS_OP_CONNECT,  SMB_VFS_LAYER_TRANSPARENT},
814
815         {SMB_VFS_OP(mkdir_acl_xattr), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_TRANSPARENT},
816         {SMB_VFS_OP(rmdir_acl_xattr), SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_TRANSPARENT},
817
818         {SMB_VFS_OP(open_acl_xattr),  SMB_VFS_OP_OPEN,  SMB_VFS_LAYER_TRANSPARENT},
819         {SMB_VFS_OP(unlink_acl_xattr), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_TRANSPARENT},
820
821         /* NT File ACL operations */
822
823         {SMB_VFS_OP(fget_nt_acl_xattr),SMB_VFS_OP_FGET_NT_ACL,SMB_VFS_LAYER_TRANSPARENT},
824         {SMB_VFS_OP(get_nt_acl_xattr), SMB_VFS_OP_GET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT},
825         {SMB_VFS_OP(fset_nt_acl_xattr),SMB_VFS_OP_FSET_NT_ACL,SMB_VFS_LAYER_TRANSPARENT},
826
827         {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
828 };
829
830 NTSTATUS vfs_acl_xattr_init(void)
831 {
832         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "acl_tdb", skel_op_tuples);
833 }