Fix bug 6938 : No hook exists to check creation rights when using acl_xattr module
[ddiss/samba.git] / source3 / modules / vfs_acl_common.c
1 /*
2  * Store Windows ACLs in data store - common functions.
3  * #included into modules/vfs_acl_xattr.c and modules/vfs_acl_tdb.c
4  *
5  * Copyright (C) Volker Lendecke, 2008
6  * Copyright (C) Jeremy Allison, 2009
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
23                         DATA_BLOB *pblob,
24                         uint16_t hash_type,
25                         uint8_t hash[XATTR_SD_HASH_SIZE]);
26
27 static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
28                         vfs_handle_struct *handle,
29                         files_struct *fsp,
30                         const char *name,
31                         DATA_BLOB *pblob);
32
33 static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
34                         files_struct *fsp,
35                         DATA_BLOB *pblob);
36
37 static NTSTATUS store_acl_blob_pathname(vfs_handle_struct *handle,
38                         const char *fname,
39                         DATA_BLOB *pblob);
40
41 #define HASH_SECURITY_INFO (OWNER_SECURITY_INFORMATION | \
42                                 GROUP_SECURITY_INFORMATION | \
43                                 DACL_SECURITY_INFORMATION | \
44                                 SACL_SECURITY_INFORMATION)
45
46 /*******************************************************************
47  Hash a security descriptor.
48 *******************************************************************/
49
50 static NTSTATUS hash_sd_sha256(struct security_descriptor *psd,
51                         uint8_t *hash)
52 {
53         DATA_BLOB blob;
54         SHA256_CTX tctx;
55         NTSTATUS status;
56
57         memset(hash, '\0', XATTR_SD_HASH_SIZE);
58         status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
59         if (!NT_STATUS_IS_OK(status)) {
60                 return status;
61         }
62
63         SHA256_Init(&tctx);
64         SHA256_Update(&tctx, blob.data, blob.length);
65         SHA256_Final(hash, &tctx);
66
67         return NT_STATUS_OK;
68 }
69
70 /*******************************************************************
71  Parse out a struct security_descriptor from a DATA_BLOB.
72 *******************************************************************/
73
74 static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
75                                 struct security_descriptor **ppdesc,
76                                 uint16_t *p_hash_type,
77                                 uint8_t hash[XATTR_SD_HASH_SIZE])
78 {
79         TALLOC_CTX *ctx = talloc_tos();
80         struct xattr_NTACL xacl;
81         enum ndr_err_code ndr_err;
82         size_t sd_size;
83
84         ndr_err = ndr_pull_struct_blob(pblob, ctx, NULL, &xacl,
85                         (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
86
87         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
88                 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
89                         ndr_errstr(ndr_err)));
90                 return ndr_map_error2ntstatus(ndr_err);;
91         }
92
93         switch (xacl.version) {
94                 case 2:
95                         *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION,
96                                         xacl.info.sd_hs2->sd->type | SEC_DESC_SELF_RELATIVE,
97                                         xacl.info.sd_hs2->sd->owner_sid,
98                                         xacl.info.sd_hs2->sd->group_sid,
99                                         xacl.info.sd_hs2->sd->sacl,
100                                         xacl.info.sd_hs2->sd->dacl,
101                                         &sd_size);
102                         /* No hash - null out. */
103                         *p_hash_type = XATTR_SD_HASH_TYPE_NONE;
104                         memset(hash, '\0', XATTR_SD_HASH_SIZE);
105                         break;
106                 case 3:
107                         *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION,
108                                         xacl.info.sd_hs3->sd->type | SEC_DESC_SELF_RELATIVE,
109                                         xacl.info.sd_hs3->sd->owner_sid,
110                                         xacl.info.sd_hs3->sd->group_sid,
111                                         xacl.info.sd_hs3->sd->sacl,
112                                         xacl.info.sd_hs3->sd->dacl,
113                                         &sd_size);
114                         *p_hash_type = xacl.info.sd_hs3->hash_type;
115                         /* Current version 3. */
116                         memcpy(hash, xacl.info.sd_hs3->hash, XATTR_SD_HASH_SIZE);
117                         break;
118                 default:
119                         return NT_STATUS_REVISION_MISMATCH;
120         }
121
122         TALLOC_FREE(xacl.info.sd);
123
124         return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
125 }
126
127 /*******************************************************************
128  Create a DATA_BLOB from a security descriptor.
129 *******************************************************************/
130
131 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
132                         DATA_BLOB *pblob,
133                         uint16_t hash_type,
134                         uint8_t hash[XATTR_SD_HASH_SIZE])
135 {
136         struct xattr_NTACL xacl;
137         struct security_descriptor_hash_v3 sd_hs3;
138         enum ndr_err_code ndr_err;
139         TALLOC_CTX *ctx = talloc_tos();
140
141         ZERO_STRUCT(xacl);
142         ZERO_STRUCT(sd_hs3);
143
144         xacl.version = 3;
145         xacl.info.sd_hs3 = &sd_hs3;
146         xacl.info.sd_hs3->sd = CONST_DISCARD(struct security_descriptor *, psd);
147         xacl.info.sd_hs3->hash_type = hash_type;
148         memcpy(&xacl.info.sd_hs3->hash[0], hash, XATTR_SD_HASH_SIZE);
149
150         ndr_err = ndr_push_struct_blob(
151                         pblob, ctx, NULL, &xacl,
152                         (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
153
154         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
155                 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
156                         ndr_errstr(ndr_err)));
157                 return ndr_map_error2ntstatus(ndr_err);;
158         }
159
160         return NT_STATUS_OK;
161 }
162
163 /*******************************************************************
164  Store a DATA_BLOB into an xattr given a pathname.
165 *******************************************************************/
166
167 static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
168                                 files_struct *fsp,
169                                 const char *name,
170                                 uint32_t security_info,
171                                 struct security_descriptor **ppdesc)
172 {
173         DATA_BLOB blob;
174         NTSTATUS status;
175         uint16_t hash_type;
176         uint8_t hash[XATTR_SD_HASH_SIZE];
177         uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
178         struct security_descriptor *pdesc_next = NULL;
179
180         if (fsp && name == NULL) {
181                 name = fsp->fsp_name->base_name;
182         }
183
184         DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));
185
186         status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
187         if (!NT_STATUS_IS_OK(status)) {
188                 DEBUG(10, ("get_acl_blob returned %s\n", nt_errstr(status)));
189                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
190                         /* Pull the ACL from the underlying system. */
191                         if (fsp) {
192                                 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
193                                                                 fsp,
194                                                                 security_info,
195                                                                 ppdesc);
196                         } else {
197                                 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
198                                                                 name,
199                                                                 security_info,
200                                                                 ppdesc);
201                         }
202                 }
203                 return status;
204         }
205
206         status = parse_acl_blob(&blob, ppdesc,
207                                 &hash_type, &hash[0]);
208         if (!NT_STATUS_IS_OK(status)) {
209                 DEBUG(10, ("parse_acl_blob returned %s\n",
210                                 nt_errstr(status)));
211                 return status;
212         }
213
214         /* Ensure the hash type is one we know. */
215         switch (hash_type) {
216                 case XATTR_SD_HASH_TYPE_NONE:
217                         /* No hash, goto return blob sd. */
218                         goto out;
219                 case XATTR_SD_HASH_TYPE_SHA256:
220                         break;
221                 default:
222                         return NT_STATUS_REVISION_MISMATCH;
223         }
224
225         /* Get the full underlying sd, then hash. */
226         if (fsp) {
227                 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
228                                 fsp,
229                                 HASH_SECURITY_INFO,
230                                 &pdesc_next);
231         } else {
232                 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
233                                 name,
234                                 HASH_SECURITY_INFO,
235                                 &pdesc_next);
236         }
237
238         if (!NT_STATUS_IS_OK(status)) {
239                 goto out;
240         }
241
242         status = hash_sd_sha256(pdesc_next, hash_tmp);
243         if (!NT_STATUS_IS_OK(status)) {
244                 goto out;
245         }
246
247         if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
248                 TALLOC_FREE(pdesc_next);
249                 /* Hash matches, return blob sd. */
250                 goto out;
251         }
252
253         /* Hash doesn't match, return underlying sd. */
254
255         if (!(security_info & OWNER_SECURITY_INFORMATION)) {
256                 pdesc_next->owner_sid = NULL;
257         }
258         if (!(security_info & GROUP_SECURITY_INFORMATION)) {
259                 pdesc_next->group_sid = NULL;
260         }
261         if (!(security_info & DACL_SECURITY_INFORMATION)) {
262                 pdesc_next->dacl = NULL;
263         }
264         if (!(security_info & SACL_SECURITY_INFORMATION)) {
265                 pdesc_next->sacl = NULL;
266         }
267
268         TALLOC_FREE(*ppdesc);
269         *ppdesc = pdesc_next;
270
271   out:
272
273         if (!(security_info & OWNER_SECURITY_INFORMATION)) {
274                 (*ppdesc)->owner_sid = NULL;
275         }
276         if (!(security_info & GROUP_SECURITY_INFORMATION)) {
277                 (*ppdesc)->group_sid = NULL;
278         }
279         if (!(security_info & DACL_SECURITY_INFORMATION)) {
280                 (*ppdesc)->dacl = NULL;
281         }
282         if (!(security_info & SACL_SECURITY_INFORMATION)) {
283                 (*ppdesc)->sacl = NULL;
284         }
285
286         TALLOC_FREE(blob.data);
287         return status;
288 }
289
290 /*********************************************************************
291  Create a default security descriptor for a file in case no inheritance
292  exists. All permissions to the owner and SYSTEM.
293 *********************************************************************/
294
295 static struct security_descriptor *default_file_sd(TALLOC_CTX *mem_ctx,
296                                                 SMB_STRUCT_STAT *psbuf,
297                                                 bool force_inherit)
298 {
299         struct dom_sid owner_sid, group_sid;
300         size_t sd_size;
301         struct security_ace *pace = NULL;
302         struct security_acl *pacl = NULL;
303
304         uid_to_sid(&owner_sid, psbuf->st_ex_uid);
305         gid_to_sid(&group_sid, psbuf->st_ex_gid);
306
307         pace = TALLOC_ARRAY(mem_ctx, struct security_ace, 2);
308         if (!pace) {
309                 return NULL;
310         }
311
312         /* If force_inherit is set, this means we are initializing the ACEs for
313          * a container and we want the ACEs for owner_sid and "SYSTEM" to be
314          * inheritable by their children (See Bug #6802).
315          */
316
317         init_sec_ace(&pace[0], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
318                         SEC_RIGHTS_FILE_ALL, (force_inherit ?
319                                         (SEC_ACE_FLAG_OBJECT_INHERIT|
320                                         SEC_ACE_FLAG_CONTAINER_INHERIT) :
321                                         0));
322
323         init_sec_ace(&pace[1], &global_sid_System, SEC_ACE_TYPE_ACCESS_ALLOWED,
324                         SEC_RIGHTS_FILE_ALL, (force_inherit ?
325                                         (SEC_ACE_FLAG_OBJECT_INHERIT|
326                                         SEC_ACE_FLAG_CONTAINER_INHERIT) :
327                                         0));
328
329         pacl = make_sec_acl(mem_ctx,
330                                 NT4_ACL_REVISION,
331                                 2,
332                                 pace);
333         if (!pacl) {
334                 return NULL;
335         }
336         return make_sec_desc(mem_ctx,
337                         SECURITY_DESCRIPTOR_REVISION_1,
338                         SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
339                         &owner_sid,
340                         &group_sid,
341                         NULL,
342                         pacl,
343                         &sd_size);
344 }
345
346 /*********************************************************************
347 *********************************************************************/
348
349 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
350                                         struct smb_filename *smb_fname,
351                                         files_struct *fsp,
352                                         bool container)
353 {
354         TALLOC_CTX *ctx = talloc_tos();
355         NTSTATUS status;
356         struct security_descriptor *parent_desc = NULL;
357         struct security_descriptor *psd = NULL;
358         struct security_descriptor *pdesc_next = NULL;
359         DATA_BLOB blob;
360         size_t size;
361         char *parent_name;
362         bool force_inherit = false;
363         uint8_t hash[XATTR_SD_HASH_SIZE];
364
365         if (!parent_dirname(ctx, smb_fname->base_name, &parent_name, NULL)) {
366                 return NT_STATUS_NO_MEMORY;
367         }
368
369         DEBUG(10,("inherit_new_acl: check directory %s\n",
370                         parent_name));
371
372         status = get_nt_acl_internal(handle,
373                                 NULL,
374                                 parent_name,
375                                 (OWNER_SECURITY_INFORMATION |
376                                  GROUP_SECURITY_INFORMATION |
377                                  DACL_SECURITY_INFORMATION),
378                                 &parent_desc);
379         if (NT_STATUS_IS_OK(status)) {
380                 /* Create an inherited descriptor from the parent. */
381
382                 if (DEBUGLEVEL >= 10) {
383                         DEBUG(10,("inherit_new_acl: parent acl is:\n"));
384                         NDR_PRINT_DEBUG(security_descriptor, parent_desc);
385                 }
386
387                 status = se_create_child_secdesc(ctx,
388                                 &psd,
389                                 &size,
390                                 parent_desc,
391                                 &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX],
392                                 &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX],
393                                 container);
394                 if (!NT_STATUS_IS_OK(status)) {
395                         return status;
396                 }
397
398                 if (DEBUGLEVEL >= 10) {
399                         DEBUG(10,("inherit_new_acl: child acl is:\n"));
400                         NDR_PRINT_DEBUG(security_descriptor, psd);
401                 }
402
403         } else {
404                 DEBUG(10,("inherit_new_acl: directory %s failed "
405                         "to get acl %s\n",
406                         parent_name,
407                         nt_errstr(status) ));
408         }
409
410         if (!psd || psd->dacl == NULL) {
411
412                 TALLOC_FREE(psd);
413                 if (fsp) {
414                         status = vfs_stat_fsp(fsp);
415                         smb_fname->st = fsp->fsp_name->st;
416                 } else {
417                         int ret;
418                         if (lp_posix_pathnames()) {
419                                 ret = SMB_VFS_LSTAT(handle->conn, smb_fname);
420                         } else {
421                                 ret = SMB_VFS_STAT(handle->conn, smb_fname);
422                         }
423                         if (ret == -1) {
424                                 status = map_nt_error_from_unix(errno);
425                         }
426                 }
427                 if (!NT_STATUS_IS_OK(status)) {
428                         return status;
429                 }
430
431                 /* If we get here, we could have the following possibilities:
432                  *      1. No ACLs exist on the parent container.
433                  *      2. ACLs exist on the parent container but they were
434                  *      not inheritable.
435                  *
436                  *      Check to see if case #1 occurred.
437                  *
438                  */
439                 if (container &&
440                         (parent_desc == NULL || parent_desc->dacl == NULL)) {
441
442                         /* If no parent descriptor exists, then there were
443                          * no ACLs on the parent and then we must create
444                          * the ACLs on this newly created folder so that they
445                          * will be inherited by their children (See Bug #6802).
446                          */
447
448                         force_inherit = true;
449                 }
450
451                 psd = default_file_sd(ctx, &smb_fname->st, force_inherit);
452                 if (!psd) {
453                         return NT_STATUS_NO_MEMORY;
454                 }
455
456                 if (DEBUGLEVEL >= 10) {
457                         DEBUG(10,("inherit_new_acl: default acl is:\n"));
458                         NDR_PRINT_DEBUG(security_descriptor, psd);
459                 }
460         }
461
462         /* Object exists. Read the current SD to get the hash. */
463         if (fsp) {
464                 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
465                                 fsp,
466                                 HASH_SECURITY_INFO,
467                                 &pdesc_next);
468         } else {
469                 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
470                                 smb_fname->base_name,
471                                 HASH_SECURITY_INFO,
472                                 &pdesc_next);
473         }
474
475         if (!NT_STATUS_IS_OK(status)) {
476                 return status;
477         }
478
479         status = hash_sd_sha256(pdesc_next, hash);
480         if (!NT_STATUS_IS_OK(status)) {
481                 return status;
482         }
483         status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
484         if (!NT_STATUS_IS_OK(status)) {
485                 return status;
486         }
487         if (fsp) {
488                 return store_acl_blob_fsp(handle, fsp, &blob);
489         } else {
490                 return store_acl_blob_pathname(handle, smb_fname->base_name,
491                                                &blob);
492         }
493 }
494
495 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
496                                 const char *path,
497                                 uint32_t access_mask)
498 {
499         char *parent_name = NULL;
500         struct security_descriptor *parent_desc = NULL;
501         uint32_t access_granted = 0;
502         NTSTATUS status;
503
504         if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
505                 return NT_STATUS_NO_MEMORY;
506         }
507
508         status = SMB_VFS_GET_NT_ACL(handle->conn,
509                                         parent_name,
510                                         (OWNER_SECURITY_INFORMATION |
511                                          GROUP_SECURITY_INFORMATION |
512                                          DACL_SECURITY_INFORMATION),
513                                         &parent_desc);
514         if (!NT_STATUS_IS_OK(status)) {
515                 DEBUG(0,("check_parent_acl_common: SMB_VFS_GET_NT_ACL "
516                         "on directory %s for "
517                         "path %s returned %s\n",
518                         parent_name,
519                         path,
520                         nt_errstr(status) ));
521                 return status;
522         }
523         status = smb1_file_se_access_check(parent_desc,
524                                         handle->conn->server_info->ptok,
525                                         access_mask,
526                                         &access_granted);
527         if(!NT_STATUS_IS_OK(status)) {
528                 DEBUG(0,("check_parent_acl_common: access check "
529                         "on directory %s for "
530                         "path %s for mask 0x%x returned %s\n",
531                         parent_name,
532                         path,
533                         access_mask,
534                         nt_errstr(status) ));
535                 return status;
536         }
537         return NT_STATUS_OK;
538 }
539
540 /*********************************************************************
541  Check ACL on open. For new files inherit from parent directory.
542 *********************************************************************/
543
544 static int open_acl_common(vfs_handle_struct *handle,
545                         struct smb_filename *smb_fname,
546                         files_struct *fsp,
547                         int flags,
548                         mode_t mode)
549 {
550         uint32_t access_granted = 0;
551         struct security_descriptor *pdesc = NULL;
552         bool file_existed = true;
553         char *fname = NULL;
554         NTSTATUS status;
555
556         if (fsp->base_fsp) {
557                 /* Stream open. Base filename open already did the ACL check. */
558                 DEBUG(10,("open_acl_common: stream open on %s\n",
559                         smb_fname_str_dbg(smb_fname) ));
560                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
561         }
562
563         status = get_full_smb_filename(talloc_tos(), smb_fname,
564                                        &fname);
565         if (!NT_STATUS_IS_OK(status)) {
566                 goto err;
567         }
568
569         status = get_nt_acl_internal(handle,
570                                 NULL,
571                                 fname,
572                                 (OWNER_SECURITY_INFORMATION |
573                                  GROUP_SECURITY_INFORMATION |
574                                  DACL_SECURITY_INFORMATION),
575                                 &pdesc);
576         if (NT_STATUS_IS_OK(status)) {
577                 /* See if we can access it. */
578                 status = smb1_file_se_access_check(pdesc,
579                                         handle->conn->server_info->ptok,
580                                         fsp->access_mask,
581                                         &access_granted);
582                 if (!NT_STATUS_IS_OK(status)) {
583                         DEBUG(10,("open_acl_xattr: file %s open "
584                                 "refused with error %s\n",
585                                 smb_fname_str_dbg(smb_fname),
586                                 nt_errstr(status) ));
587                         goto err;
588                 }
589         } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
590                 file_existed = false;
591                 /*
592                  * If O_CREAT is true then we're trying to create a file.
593                  * Check the parent directory ACL will allow this.
594                  */
595                 if (flags & O_CREAT) {
596                         status = check_parent_acl_common(handle, fname,
597                                         SEC_DIR_ADD_FILE);
598                         if (!NT_STATUS_IS_OK(status)) {
599                                 goto err;
600                         }
601                 }
602         }
603
604         DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
605                 "file %s returned %s\n",
606                 smb_fname_str_dbg(smb_fname),
607                 nt_errstr(status) ));
608
609         fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
610
611         if (!file_existed && fsp->fh->fd != -1) {
612                 /* File was created. Inherit from parent directory. */
613                 status = fsp_set_smb_fname(fsp, smb_fname);
614                 if (!NT_STATUS_IS_OK(status)) {
615                         goto err;
616                 }
617                 inherit_new_acl(handle, smb_fname, fsp, false);
618         }
619
620         return fsp->fh->fd;
621
622   err:
623
624         errno = map_errno_from_nt_status(status);
625         return -1;
626 }
627
628 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
629 {
630         struct smb_filename *smb_fname = NULL;
631         int ret;
632         NTSTATUS status;
633         SMB_STRUCT_STAT sbuf;
634
635         ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
636         if (ret == -1 && errno == ENOENT) {
637                 /* We're creating a new directory. */
638                 status = check_parent_acl_common(handle, path,
639                                 SEC_DIR_ADD_SUBDIR);
640                 if (!NT_STATUS_IS_OK(status)) {
641                         errno = map_errno_from_nt_status(status);
642                         return -1;
643                 }
644         }
645
646         ret = SMB_VFS_NEXT_MKDIR(handle, path, mode);
647         if (ret == -1) {
648                 return ret;
649         }
650
651         status = create_synthetic_smb_fname(talloc_tos(), path, NULL, NULL,
652                                             &smb_fname);
653         if (!NT_STATUS_IS_OK(status)) {
654                 errno = map_errno_from_nt_status(status);
655                 return -1;
656         }
657
658         /* New directory - inherit from parent. */
659         inherit_new_acl(handle, smb_fname, NULL, true);
660         TALLOC_FREE(smb_fname);
661         return ret;
662 }
663
664 /*********************************************************************
665  Fetch a security descriptor given an fsp.
666 *********************************************************************/
667
668 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
669         uint32_t security_info, struct security_descriptor **ppdesc)
670 {
671         return get_nt_acl_internal(handle, fsp,
672                                 NULL, security_info, ppdesc);
673 }
674
675 /*********************************************************************
676  Fetch a security descriptor given a pathname.
677 *********************************************************************/
678
679 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
680         const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
681 {
682         return get_nt_acl_internal(handle, NULL,
683                                 name, security_info, ppdesc);
684 }
685
686 /*********************************************************************
687  Store a security descriptor given an fsp.
688 *********************************************************************/
689
690 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
691         uint32_t security_info_sent, const struct security_descriptor *psd)
692 {
693         NTSTATUS status;
694         DATA_BLOB blob;
695         struct security_descriptor *pdesc_next = NULL;
696         uint8_t hash[XATTR_SD_HASH_SIZE];
697
698         if (DEBUGLEVEL >= 10) {
699                 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
700                           fsp_str_dbg(fsp)));
701                 NDR_PRINT_DEBUG(security_descriptor,
702                         CONST_DISCARD(struct security_descriptor *,psd));
703         }
704
705         /* Ensure we have OWNER/GROUP/DACL set. */
706
707         if ((security_info_sent & (OWNER_SECURITY_INFORMATION|
708                                 GROUP_SECURITY_INFORMATION|
709                                 DACL_SECURITY_INFORMATION)) !=
710                                 (OWNER_SECURITY_INFORMATION|
711                                  GROUP_SECURITY_INFORMATION|
712                                  DACL_SECURITY_INFORMATION)) {
713                 /* No we don't - read from the existing SD. */
714                 struct security_descriptor *nc_psd = NULL;
715
716                 status = get_nt_acl_internal(handle, fsp,
717                                 NULL,
718                                 (OWNER_SECURITY_INFORMATION|
719                                  GROUP_SECURITY_INFORMATION|
720                                  DACL_SECURITY_INFORMATION),
721                                 &nc_psd);
722
723                 if (!NT_STATUS_IS_OK(status)) {
724                         return status;
725                 }
726
727                 /* This is safe as nc_psd is discarded at fn exit. */
728                 if (security_info_sent & OWNER_SECURITY_INFORMATION) {
729                         nc_psd->owner_sid = psd->owner_sid;
730                 }
731                 security_info_sent |= OWNER_SECURITY_INFORMATION;
732
733                 if (security_info_sent & GROUP_SECURITY_INFORMATION) {
734                         nc_psd->group_sid = psd->group_sid;
735                 }
736                 security_info_sent |= GROUP_SECURITY_INFORMATION;
737
738                 if (security_info_sent & DACL_SECURITY_INFORMATION) {
739                         nc_psd->dacl = dup_sec_acl(talloc_tos(), psd->dacl);
740                         if (nc_psd->dacl == NULL) {
741                                 return NT_STATUS_NO_MEMORY;
742                         }
743                 }
744                 security_info_sent |= DACL_SECURITY_INFORMATION;
745                 psd = nc_psd;
746         }
747
748         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
749         if (!NT_STATUS_IS_OK(status)) {
750                 return status;
751         }
752
753         /* Get the full underlying sd, then hash. */
754         status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
755                                 fsp,
756                                 HASH_SECURITY_INFO,
757                                 &pdesc_next);
758
759         if (!NT_STATUS_IS_OK(status)) {
760                 return status;
761         }
762
763         status = hash_sd_sha256(pdesc_next, hash);
764         if (!NT_STATUS_IS_OK(status)) {
765                 return status;
766         }
767
768         if (DEBUGLEVEL >= 10) {
769                 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
770                           fsp_str_dbg(fsp)));
771                 NDR_PRINT_DEBUG(security_descriptor,
772                         CONST_DISCARD(struct security_descriptor *,psd));
773         }
774         create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
775         store_acl_blob_fsp(handle, fsp, &blob);
776
777         return NT_STATUS_OK;
778 }
779
780 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
781                         const char *fname, const char *mask, uint32 attr)
782 {
783         NTSTATUS status = check_parent_acl_common(handle, fname, SEC_DIR_LIST);
784
785         if (!NT_STATUS_IS_OK(status)) {
786         }
787         return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
788 }