Restructure the ACL code some more, get the internal semantics
[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  Pull a DATA_BLOB from an xattr given a pathname.
165  If the hash doesn't match, or doesn't exist - return the underlying
166  filesystem sd.
167 *******************************************************************/
168
169 static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
170                                 files_struct *fsp,
171                                 const char *name,
172                                 uint32_t security_info,
173                                 struct security_descriptor **ppdesc)
174 {
175         DATA_BLOB blob;
176         NTSTATUS status;
177         uint16_t hash_type;
178         uint8_t hash[XATTR_SD_HASH_SIZE];
179         uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
180         struct security_descriptor *psd = NULL;
181         struct security_descriptor *pdesc_next = NULL;
182
183         if (fsp && name == NULL) {
184                 name = fsp->fsp_name->base_name;
185         }
186
187         DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));
188
189         /* Get the full underlying sd for the hash
190            or to return as backup. */
191         if (fsp) {
192                 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
193                                 fsp,
194                                 HASH_SECURITY_INFO,
195                                 &pdesc_next);
196         } else {
197                 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
198                                 name,
199                                 HASH_SECURITY_INFO,
200                                 &pdesc_next);
201         }
202
203         if (!NT_STATUS_IS_OK(status)) {
204                 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
205                         "returned %s\n",
206                         name,
207                         nt_errstr(status)));
208                 return status;
209         }
210
211         status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
212         if (!NT_STATUS_IS_OK(status)) {
213                 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
214                         nt_errstr(status)));
215                 psd = pdesc_next;
216                 goto out;
217         }
218
219         status = parse_acl_blob(&blob, &psd,
220                                 &hash_type, &hash[0]);
221         if (!NT_STATUS_IS_OK(status)) {
222                 DEBUG(10, ("parse_acl_blob returned %s\n",
223                                 nt_errstr(status)));
224                 psd = pdesc_next;
225                 goto out;
226         }
227
228         /* Ensure the hash type is one we know. */
229         switch (hash_type) {
230                 case XATTR_SD_HASH_TYPE_NONE:
231                         /* No hash, just return blob sd. */
232                         goto out;
233                 case XATTR_SD_HASH_TYPE_SHA256:
234                         break;
235                 default:
236                         DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
237                                 "mismatch (%u) for file %s\n",
238                                 (unsigned int)hash_type,
239                                 name));
240                         TALLOC_FREE(psd);
241                         psd = pdesc_next;
242                         goto out;
243         }
244
245
246         status = hash_sd_sha256(pdesc_next, hash_tmp);
247         if (!NT_STATUS_IS_OK(status)) {
248                 TALLOC_FREE(psd);
249                 psd = pdesc_next;
250                 goto out;
251         }
252
253         if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
254                 /* Hash matches, return blob sd. */
255                 goto out;
256         }
257
258         /* Hash doesn't match, return underlying sd. */
259         TALLOC_FREE(psd);
260         psd = pdesc_next;
261
262   out:
263
264         if (psd != pdesc_next) {
265                 /* We're returning the blob, throw
266                  * away the filesystem SD. */
267                 TALLOC_FREE(pdesc_next);
268         }
269
270         if (!(security_info & OWNER_SECURITY_INFORMATION)) {
271                 psd->owner_sid = NULL;
272         }
273         if (!(security_info & GROUP_SECURITY_INFORMATION)) {
274                 psd->group_sid = NULL;
275         }
276         if (!(security_info & DACL_SECURITY_INFORMATION)) {
277                 psd->dacl = NULL;
278         }
279         if (!(security_info & SACL_SECURITY_INFORMATION)) {
280                 psd->sacl = NULL;
281         }
282
283         TALLOC_FREE(blob.data);
284         *ppdesc = psd;
285         return NT_STATUS_OK;
286 }
287
288 #if 0
289 /*********************************************************************
290  Create a default security descriptor for a file in case no inheritance
291  exists. All permissions to the owner and SYSTEM.
292 *********************************************************************/
293
294 static struct security_descriptor *default_file_sd(TALLOC_CTX *mem_ctx,
295                                                 SMB_STRUCT_STAT *psbuf,
296                                                 bool force_inherit)
297 {
298         struct dom_sid owner_sid, group_sid;
299         size_t sd_size;
300         struct security_ace *pace = NULL;
301         struct security_acl *pacl = NULL;
302
303         uid_to_sid(&owner_sid, psbuf->st_ex_uid);
304         gid_to_sid(&group_sid, psbuf->st_ex_gid);
305
306         pace = TALLOC_ARRAY(mem_ctx, struct security_ace, 2);
307         if (!pace) {
308                 return NULL;
309         }
310
311         /* If force_inherit is set, this means we are initializing the ACEs for
312          * a container and we want the ACEs for owner_sid and "SYSTEM" to be
313          * inheritable by their children (See Bug #6802).
314          */
315
316         init_sec_ace(&pace[0], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
317                         SEC_RIGHTS_FILE_ALL, (force_inherit ?
318                                         (SEC_ACE_FLAG_OBJECT_INHERIT|
319                                         SEC_ACE_FLAG_CONTAINER_INHERIT) :
320                                         0));
321
322         init_sec_ace(&pace[1], &global_sid_System, SEC_ACE_TYPE_ACCESS_ALLOWED,
323                         SEC_RIGHTS_FILE_ALL, (force_inherit ?
324                                         (SEC_ACE_FLAG_OBJECT_INHERIT|
325                                         SEC_ACE_FLAG_CONTAINER_INHERIT) :
326                                         0));
327
328         pacl = make_sec_acl(mem_ctx,
329                                 NT4_ACL_REVISION,
330                                 2,
331                                 pace);
332         if (!pacl) {
333                 return NULL;
334         }
335         return make_sec_desc(mem_ctx,
336                         SECURITY_DESCRIPTOR_REVISION_1,
337                         SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
338                         &owner_sid,
339                         &group_sid,
340                         NULL,
341                         pacl,
342                         &sd_size);
343 }
344 #endif
345
346 /*********************************************************************
347  Create a default ACL by inheriting from the parent. If no inheritance
348  from the parent available, just use the actual permissions the new
349  file or directory already got from the filesystem.
350 *********************************************************************/
351
352 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
353                                         struct smb_filename *smb_fname,
354                                         files_struct *fsp,
355                                         struct security_descriptor *parent_desc,
356                                         bool is_directory)
357 {
358         TALLOC_CTX *ctx = talloc_tos();
359         NTSTATUS status = NT_STATUS_OK;
360         struct security_descriptor *psd = NULL;
361         struct security_descriptor *pdesc_next = NULL;
362         DATA_BLOB blob;
363         size_t size;
364         uint8_t hash[XATTR_SD_HASH_SIZE];
365
366         if (parent_desc == NULL) {
367                 /* We don't already have the parent sd, fetch it now. */
368                 char *parent_name;
369
370                 if (!parent_dirname(ctx, smb_fname->base_name, &parent_name, NULL)) {
371                         return NT_STATUS_NO_MEMORY;
372                 }
373
374                 DEBUG(10,("inherit_new_acl: check directory %s\n",
375                                 parent_name));
376
377                 status = get_nt_acl_internal(handle,
378                                 NULL,
379                                 parent_name,
380                                 (OWNER_SECURITY_INFORMATION |
381                                  GROUP_SECURITY_INFORMATION |
382                                  DACL_SECURITY_INFORMATION),
383                                 &parent_desc);
384
385                 if (!NT_STATUS_IS_OK(status)) {
386                         DEBUG(10,("inherit_new_acl: directory %s failed "
387                                 "to get acl BLOB %s\n",
388                                 parent_name,
389                                 nt_errstr(status) ));
390                         return status;
391                 }
392         }
393
394         /*
395          * Object must exist. Read the current SD off the filesystem
396          * for the hash.
397          */
398         if (fsp) {
399                 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
400                                 fsp,
401                                 HASH_SECURITY_INFO,
402                                 &pdesc_next);
403         } else {
404                 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
405                                 smb_fname->base_name,
406                                 HASH_SECURITY_INFO,
407                                 &pdesc_next);
408         }
409
410         if (!NT_STATUS_IS_OK(status)) {
411                 DEBUG(10,("inherit_new_acl: get_next_acl \n"
412                         "failed for %s (%s)\n",
413                         smb_fname_str_dbg(smb_fname),
414                         nt_errstr(status) ));
415                 return status;
416         }
417
418         if (parent_desc && sd_has_inheritable_components(parent_desc, is_directory)) {
419                 /* Create an inherited descriptor from the parent. */
420
421                 if (DEBUGLEVEL >= 10) {
422                         DEBUG(10,("inherit_new_acl: parent acl is:\n"));
423                         NDR_PRINT_DEBUG(security_descriptor, parent_desc);
424                 }
425
426                 status = se_create_child_secdesc(ctx,
427                                 &psd,
428                                 &size,
429                                 parent_desc,
430                                 &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX],
431                                 &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX],
432                                 is_directory);
433                 if (!NT_STATUS_IS_OK(status)) {
434                         return status;
435                 }
436
437         } else {
438                 DEBUG(10,("inherit_new_acl: using current permissions.\n"
439                         "to set Windows acl for %s\n",
440                         smb_fname_str_dbg(smb_fname) ));
441                 psd = pdesc_next;
442         }
443
444         if (DEBUGLEVEL >= 10) {
445                 DEBUG(10,("inherit_new_acl: child acl is:\n"));
446                 NDR_PRINT_DEBUG(security_descriptor, psd);
447         }
448
449         status = hash_sd_sha256(pdesc_next, hash);
450         if (!NT_STATUS_IS_OK(status)) {
451                 return status;
452         }
453         status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
454         if (!NT_STATUS_IS_OK(status)) {
455                 return status;
456         }
457         if (fsp) {
458                 return store_acl_blob_fsp(handle, fsp, &blob);
459         } else {
460                 return store_acl_blob_pathname(handle, smb_fname->base_name,
461                                                &blob);
462         }
463 }
464
465 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
466                                 const char *path,
467                                 uint32_t access_mask,
468                                 struct security_descriptor **pp_parent_desc)
469 {
470         char *parent_name = NULL;
471         struct security_descriptor *parent_desc = NULL;
472         uint32_t access_granted = 0;
473         NTSTATUS status;
474
475         if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
476                 return NT_STATUS_NO_MEMORY;
477         }
478
479         status = get_nt_acl_internal(handle,
480                                         NULL,
481                                         parent_name,
482                                         (OWNER_SECURITY_INFORMATION |
483                                          GROUP_SECURITY_INFORMATION |
484                                          DACL_SECURITY_INFORMATION),
485                                         &parent_desc);
486
487         if (!NT_STATUS_IS_OK(status)) {
488                 DEBUG(10,("check_parent_acl_common: get_nt_acl_internal "
489                         "on directory %s for "
490                         "path %s returned %s\n",
491                         parent_name,
492                         path,
493                         nt_errstr(status) ));
494                 return status;
495         }
496         status = smb1_file_se_access_check(parent_desc,
497                                         handle->conn->server_info->ptok,
498                                         access_mask,
499                                         &access_granted);
500         if(!NT_STATUS_IS_OK(status)) {
501                 DEBUG(10,("check_parent_acl_common: access check "
502                         "on directory %s for "
503                         "path %s for mask 0x%x returned %s\n",
504                         parent_name,
505                         path,
506                         access_mask,
507                         nt_errstr(status) ));
508                 return status;
509         }
510         if (pp_parent_desc) {
511                 *pp_parent_desc = parent_desc;
512         }
513         return NT_STATUS_OK;
514 }
515
516 /*********************************************************************
517  Check ACL on open. For new files inherit from parent directory.
518 *********************************************************************/
519
520 static int open_acl_common(vfs_handle_struct *handle,
521                         struct smb_filename *smb_fname,
522                         files_struct *fsp,
523                         int flags,
524                         mode_t mode)
525 {
526         uint32_t access_granted = 0;
527         struct security_descriptor *pdesc = NULL;
528         struct security_descriptor *parent_desc = NULL;
529         bool file_existed = true;
530         char *fname = NULL;
531         NTSTATUS status;
532
533         if (fsp->base_fsp) {
534                 /* Stream open. Base filename open already did the ACL check. */
535                 DEBUG(10,("open_acl_common: stream open on %s\n",
536                         smb_fname_str_dbg(smb_fname) ));
537                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
538         }
539
540         status = get_full_smb_filename(talloc_tos(), smb_fname,
541                                        &fname);
542         if (!NT_STATUS_IS_OK(status)) {
543                 goto err;
544         }
545
546         status = get_nt_acl_internal(handle,
547                                 NULL,
548                                 fname,
549                                 (OWNER_SECURITY_INFORMATION |
550                                  GROUP_SECURITY_INFORMATION |
551                                  DACL_SECURITY_INFORMATION),
552                                 &pdesc);
553         if (NT_STATUS_IS_OK(status)) {
554                 /* See if we can access it. */
555                 status = smb1_file_se_access_check(pdesc,
556                                         handle->conn->server_info->ptok,
557                                         fsp->access_mask,
558                                         &access_granted);
559                 if (!NT_STATUS_IS_OK(status)) {
560                         DEBUG(10,("open_acl_xattr: file %s open "
561                                 "refused with error %s\n",
562                                 smb_fname_str_dbg(smb_fname),
563                                 nt_errstr(status) ));
564                         goto err;
565                 }
566         } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
567                 file_existed = false;
568                 /*
569                  * If O_CREAT is true then we're trying to create a file.
570                  * Check the parent directory ACL will allow this.
571                  */
572                 if (flags & O_CREAT) {
573                         status = check_parent_acl_common(handle, fname,
574                                         SEC_DIR_ADD_FILE, &parent_desc);
575                         if (!NT_STATUS_IS_OK(status)) {
576                                 goto err;
577                         }
578                 }
579         }
580
581         DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
582                 "file %s returned %s\n",
583                 smb_fname_str_dbg(smb_fname),
584                 nt_errstr(status) ));
585
586         fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
587
588         if (!file_existed && fsp->fh->fd != -1) {
589                 /* File was created. Inherit from parent directory. */
590                 status = fsp_set_smb_fname(fsp, smb_fname);
591                 if (!NT_STATUS_IS_OK(status)) {
592                         goto err;
593                 }
594                 inherit_new_acl(handle, smb_fname, fsp, parent_desc, false);
595         }
596
597         return fsp->fh->fd;
598
599   err:
600
601         errno = map_errno_from_nt_status(status);
602         return -1;
603 }
604
605 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
606 {
607         struct smb_filename *smb_fname = NULL;
608         int ret;
609         NTSTATUS status;
610         SMB_STRUCT_STAT sbuf;
611         struct security_descriptor *parent_desc = NULL;
612
613         ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
614         if (ret == -1 && errno == ENOENT) {
615                 /* We're creating a new directory. */
616                 status = check_parent_acl_common(handle, path,
617                                 SEC_DIR_ADD_SUBDIR, &parent_desc);
618                 if (!NT_STATUS_IS_OK(status)) {
619                         errno = map_errno_from_nt_status(status);
620                         return -1;
621                 }
622         }
623
624         ret = SMB_VFS_NEXT_MKDIR(handle, path, mode);
625         if (ret == -1) {
626                 return ret;
627         }
628
629         status = create_synthetic_smb_fname(talloc_tos(), path, NULL, NULL,
630                                             &smb_fname);
631         if (!NT_STATUS_IS_OK(status)) {
632                 errno = map_errno_from_nt_status(status);
633                 return -1;
634         }
635
636         /* New directory - inherit from parent. */
637         inherit_new_acl(handle, smb_fname, NULL, parent_desc, true);
638         TALLOC_FREE(smb_fname);
639         return ret;
640 }
641
642 /*********************************************************************
643  Fetch a security descriptor given an fsp.
644 *********************************************************************/
645
646 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
647         uint32_t security_info, struct security_descriptor **ppdesc)
648 {
649         return get_nt_acl_internal(handle, fsp,
650                                 NULL, security_info, ppdesc);
651 }
652
653 /*********************************************************************
654  Fetch a security descriptor given a pathname.
655 *********************************************************************/
656
657 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
658         const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
659 {
660         return get_nt_acl_internal(handle, NULL,
661                                 name, security_info, ppdesc);
662 }
663
664 /*********************************************************************
665  Store a security descriptor given an fsp.
666 *********************************************************************/
667
668 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
669         uint32_t security_info_sent, const struct security_descriptor *psd)
670 {
671         NTSTATUS status;
672         DATA_BLOB blob;
673         struct security_descriptor *pdesc_next = NULL;
674         uint8_t hash[XATTR_SD_HASH_SIZE];
675
676         if (DEBUGLEVEL >= 10) {
677                 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
678                           fsp_str_dbg(fsp)));
679                 NDR_PRINT_DEBUG(security_descriptor,
680                         CONST_DISCARD(struct security_descriptor *,psd));
681         }
682
683         /* Ensure we have OWNER/GROUP/DACL set. */
684
685         if ((security_info_sent & (OWNER_SECURITY_INFORMATION|
686                                 GROUP_SECURITY_INFORMATION|
687                                 DACL_SECURITY_INFORMATION)) !=
688                                 (OWNER_SECURITY_INFORMATION|
689                                  GROUP_SECURITY_INFORMATION|
690                                  DACL_SECURITY_INFORMATION)) {
691                 /* No we don't - read from the existing SD. */
692                 struct security_descriptor *nc_psd = NULL;
693
694                 status = get_nt_acl_internal(handle, fsp,
695                                 NULL,
696                                 (OWNER_SECURITY_INFORMATION|
697                                  GROUP_SECURITY_INFORMATION|
698                                  DACL_SECURITY_INFORMATION),
699                                 &nc_psd);
700
701                 if (!NT_STATUS_IS_OK(status)) {
702                         return status;
703                 }
704
705                 /* This is safe as nc_psd is discarded at fn exit. */
706                 if (security_info_sent & OWNER_SECURITY_INFORMATION) {
707                         nc_psd->owner_sid = psd->owner_sid;
708                 }
709                 security_info_sent |= OWNER_SECURITY_INFORMATION;
710
711                 if (security_info_sent & GROUP_SECURITY_INFORMATION) {
712                         nc_psd->group_sid = psd->group_sid;
713                 }
714                 security_info_sent |= GROUP_SECURITY_INFORMATION;
715
716                 if (security_info_sent & DACL_SECURITY_INFORMATION) {
717                         nc_psd->dacl = dup_sec_acl(talloc_tos(), psd->dacl);
718                         if (nc_psd->dacl == NULL) {
719                                 return NT_STATUS_NO_MEMORY;
720                         }
721                 }
722                 security_info_sent |= DACL_SECURITY_INFORMATION;
723                 psd = nc_psd;
724         }
725
726         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
727         if (!NT_STATUS_IS_OK(status)) {
728                 return status;
729         }
730
731         /* Get the full underlying sd, then hash. */
732         status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
733                                 fsp,
734                                 HASH_SECURITY_INFO,
735                                 &pdesc_next);
736
737         if (!NT_STATUS_IS_OK(status)) {
738                 return status;
739         }
740
741         status = hash_sd_sha256(pdesc_next, hash);
742         if (!NT_STATUS_IS_OK(status)) {
743                 return status;
744         }
745
746         if (DEBUGLEVEL >= 10) {
747                 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
748                           fsp_str_dbg(fsp)));
749                 NDR_PRINT_DEBUG(security_descriptor,
750                         CONST_DISCARD(struct security_descriptor *,psd));
751         }
752         create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
753         store_acl_blob_fsp(handle, fsp, &blob);
754
755         return NT_STATUS_OK;
756 }
757
758 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
759                         const char *fname, const char *mask, uint32 attr)
760 {
761         NTSTATUS status = check_parent_acl_common(handle, fname,
762                                         SEC_DIR_LIST, NULL);
763
764         if (!NT_STATUS_IS_OK(status)) {
765                 errno = map_errno_from_nt_status(status);
766                 return NULL;
767         }
768         return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
769 }