s3: Remove use of iconv_convenience.
[nivanova/samba-autobuild/.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 #define HASH_SECURITY_INFO (OWNER_SECURITY_INFORMATION | \
38                                 GROUP_SECURITY_INFORMATION | \
39                                 DACL_SECURITY_INFORMATION | \
40                                 SACL_SECURITY_INFORMATION)
41
42 /*******************************************************************
43  Hash a security descriptor.
44 *******************************************************************/
45
46 static NTSTATUS hash_sd_sha256(struct security_descriptor *psd,
47                         uint8_t *hash)
48 {
49         DATA_BLOB blob;
50         SHA256_CTX tctx;
51         NTSTATUS status;
52
53         memset(hash, '\0', XATTR_SD_HASH_SIZE);
54         status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
55         if (!NT_STATUS_IS_OK(status)) {
56                 return status;
57         }
58
59         SHA256_Init(&tctx);
60         SHA256_Update(&tctx, blob.data, blob.length);
61         SHA256_Final(hash, &tctx);
62
63         return NT_STATUS_OK;
64 }
65
66 /*******************************************************************
67  Parse out a struct security_descriptor from a DATA_BLOB.
68 *******************************************************************/
69
70 static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
71                                 struct security_descriptor **ppdesc,
72                                 uint16_t *p_hash_type,
73                                 uint8_t hash[XATTR_SD_HASH_SIZE])
74 {
75         TALLOC_CTX *ctx = talloc_tos();
76         struct xattr_NTACL xacl;
77         enum ndr_err_code ndr_err;
78         size_t sd_size;
79
80         ndr_err = ndr_pull_struct_blob(pblob, ctx, &xacl,
81                         (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
82
83         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
84                 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
85                         ndr_errstr(ndr_err)));
86                 return ndr_map_error2ntstatus(ndr_err);;
87         }
88
89         switch (xacl.version) {
90                 case 2:
91                         *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION,
92                                         xacl.info.sd_hs2->sd->type | SEC_DESC_SELF_RELATIVE,
93                                         xacl.info.sd_hs2->sd->owner_sid,
94                                         xacl.info.sd_hs2->sd->group_sid,
95                                         xacl.info.sd_hs2->sd->sacl,
96                                         xacl.info.sd_hs2->sd->dacl,
97                                         &sd_size);
98                         /* No hash - null out. */
99                         *p_hash_type = XATTR_SD_HASH_TYPE_NONE;
100                         memset(hash, '\0', XATTR_SD_HASH_SIZE);
101                         break;
102                 case 3:
103                         *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION,
104                                         xacl.info.sd_hs3->sd->type | SEC_DESC_SELF_RELATIVE,
105                                         xacl.info.sd_hs3->sd->owner_sid,
106                                         xacl.info.sd_hs3->sd->group_sid,
107                                         xacl.info.sd_hs3->sd->sacl,
108                                         xacl.info.sd_hs3->sd->dacl,
109                                         &sd_size);
110                         *p_hash_type = xacl.info.sd_hs3->hash_type;
111                         /* Current version 3. */
112                         memcpy(hash, xacl.info.sd_hs3->hash, XATTR_SD_HASH_SIZE);
113                         break;
114                 default:
115                         return NT_STATUS_REVISION_MISMATCH;
116         }
117
118         TALLOC_FREE(xacl.info.sd);
119
120         return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
121 }
122
123 /*******************************************************************
124  Create a DATA_BLOB from a security descriptor.
125 *******************************************************************/
126
127 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
128                         DATA_BLOB *pblob,
129                         uint16_t hash_type,
130                         uint8_t hash[XATTR_SD_HASH_SIZE])
131 {
132         struct xattr_NTACL xacl;
133         struct security_descriptor_hash_v3 sd_hs3;
134         enum ndr_err_code ndr_err;
135         TALLOC_CTX *ctx = talloc_tos();
136
137         ZERO_STRUCT(xacl);
138         ZERO_STRUCT(sd_hs3);
139
140         xacl.version = 3;
141         xacl.info.sd_hs3 = &sd_hs3;
142         xacl.info.sd_hs3->sd = CONST_DISCARD(struct security_descriptor *, psd);
143         xacl.info.sd_hs3->hash_type = hash_type;
144         memcpy(&xacl.info.sd_hs3->hash[0], hash, XATTR_SD_HASH_SIZE);
145
146         ndr_err = ndr_push_struct_blob(
147                         pblob, ctx, &xacl,
148                         (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
149
150         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
151                 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
152                         ndr_errstr(ndr_err)));
153                 return ndr_map_error2ntstatus(ndr_err);;
154         }
155
156         return NT_STATUS_OK;
157 }
158
159 /*******************************************************************
160  Add in 3 inheritable components for a non-inheritable directory ACL.
161  CREATOR_OWNER/CREATOR_GROUP/WORLD.
162 *******************************************************************/
163
164 static void add_directory_inheritable_components(vfs_handle_struct *handle,
165                                 const char *name,
166                                 SMB_STRUCT_STAT *psbuf,
167                                 struct security_descriptor *psd)
168 {
169         struct connection_struct *conn = handle->conn;
170         int num_aces = (psd->dacl ? psd->dacl->num_aces : 0);
171         struct smb_filename smb_fname;
172         enum security_ace_type acltype;
173         uint32_t access_mask;
174         mode_t dir_mode;
175         mode_t file_mode;
176         mode_t mode;
177         struct security_ace *new_ace_list = TALLOC_ZERO_ARRAY(talloc_tos(),
178                                                 struct security_ace,
179                                                 num_aces + 3);
180
181         if (new_ace_list == NULL) {
182                 return;
183         }
184
185         /* Fake a quick smb_filename. */
186         ZERO_STRUCT(smb_fname);
187         smb_fname.st = *psbuf;
188         smb_fname.base_name = CONST_DISCARD(char *, name);
189
190         dir_mode = unix_mode(conn,
191                         FILE_ATTRIBUTE_DIRECTORY, &smb_fname, NULL);
192         file_mode = unix_mode(conn,
193                         FILE_ATTRIBUTE_ARCHIVE, &smb_fname, NULL);
194
195         mode = dir_mode | file_mode;
196
197         DEBUG(10, ("add_directory_inheritable_components: directory %s, "
198                 "mode = 0%o\n",
199                 name,
200                 (unsigned int)mode ));
201
202         if (num_aces) {
203                 memcpy(new_ace_list, psd->dacl->aces,
204                         num_aces * sizeof(struct security_ace));
205         }
206         access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
207                                 mode & 0700, false);
208
209         init_sec_ace(&new_ace_list[num_aces],
210                         &global_sid_Creator_Owner,
211                         acltype,
212                         access_mask,
213                         SEC_ACE_FLAG_CONTAINER_INHERIT|
214                                 SEC_ACE_FLAG_OBJECT_INHERIT|
215                                 SEC_ACE_FLAG_INHERIT_ONLY);
216         access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
217                                 (mode << 3) & 0700, false);
218         init_sec_ace(&new_ace_list[num_aces+1],
219                         &global_sid_Creator_Group,
220                         acltype,
221                         access_mask,
222                         SEC_ACE_FLAG_CONTAINER_INHERIT|
223                                 SEC_ACE_FLAG_OBJECT_INHERIT|
224                                 SEC_ACE_FLAG_INHERIT_ONLY);
225         access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
226                                 (mode << 6) & 0700, false);
227         init_sec_ace(&new_ace_list[num_aces+2],
228                         &global_sid_World,
229                         acltype,
230                         access_mask,
231                         SEC_ACE_FLAG_CONTAINER_INHERIT|
232                                 SEC_ACE_FLAG_OBJECT_INHERIT|
233                                 SEC_ACE_FLAG_INHERIT_ONLY);
234         psd->dacl->aces = new_ace_list;
235         psd->dacl->num_aces += 3;
236 }
237
238 /*******************************************************************
239  Pull a DATA_BLOB from an xattr given a pathname.
240  If the hash doesn't match, or doesn't exist - return the underlying
241  filesystem sd.
242 *******************************************************************/
243
244 static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
245                                 files_struct *fsp,
246                                 const char *name,
247                                 uint32_t security_info,
248                                 struct security_descriptor **ppdesc)
249 {
250         DATA_BLOB blob;
251         NTSTATUS status;
252         uint16_t hash_type;
253         uint8_t hash[XATTR_SD_HASH_SIZE];
254         uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
255         struct security_descriptor *psd = NULL;
256         struct security_descriptor *pdesc_next = NULL;
257
258         if (fsp && name == NULL) {
259                 name = fsp->fsp_name->base_name;
260         }
261
262         DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));
263
264         /* Get the full underlying sd for the hash
265            or to return as backup. */
266         if (fsp) {
267                 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
268                                 fsp,
269                                 HASH_SECURITY_INFO,
270                                 &pdesc_next);
271         } else {
272                 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
273                                 name,
274                                 HASH_SECURITY_INFO,
275                                 &pdesc_next);
276         }
277
278         if (!NT_STATUS_IS_OK(status)) {
279                 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
280                         "returned %s\n",
281                         name,
282                         nt_errstr(status)));
283                 return status;
284         }
285
286         status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
287         if (!NT_STATUS_IS_OK(status)) {
288                 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
289                         nt_errstr(status)));
290                 psd = pdesc_next;
291                 goto out;
292         }
293
294         status = parse_acl_blob(&blob, &psd,
295                                 &hash_type, &hash[0]);
296         if (!NT_STATUS_IS_OK(status)) {
297                 DEBUG(10, ("parse_acl_blob returned %s\n",
298                                 nt_errstr(status)));
299                 psd = pdesc_next;
300                 goto out;
301         }
302
303         /* Ensure the hash type is one we know. */
304         switch (hash_type) {
305                 case XATTR_SD_HASH_TYPE_NONE:
306                         /* No hash, just return blob sd. */
307                         goto out;
308                 case XATTR_SD_HASH_TYPE_SHA256:
309                         break;
310                 default:
311                         DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
312                                 "mismatch (%u) for file %s\n",
313                                 (unsigned int)hash_type,
314                                 name));
315                         TALLOC_FREE(psd);
316                         psd = pdesc_next;
317                         goto out;
318         }
319
320
321         status = hash_sd_sha256(pdesc_next, hash_tmp);
322         if (!NT_STATUS_IS_OK(status)) {
323                 TALLOC_FREE(psd);
324                 psd = pdesc_next;
325                 goto out;
326         }
327
328         if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
329                 /* Hash matches, return blob sd. */
330                 goto out;
331         }
332
333         /* Hash doesn't match, return underlying sd. */
334         TALLOC_FREE(psd);
335         psd = pdesc_next;
336
337   out:
338
339         if (psd != pdesc_next) {
340                 /* We're returning the blob, throw
341                  * away the filesystem SD. */
342                 TALLOC_FREE(pdesc_next);
343         } else {
344                 SMB_STRUCT_STAT sbuf;
345                 SMB_STRUCT_STAT *psbuf = &sbuf;
346                 bool is_directory = false;
347                 /*
348                  * We're returning the underlying ACL from the
349                  * filesystem. If it's a directory, and has no
350                  * inheritable ACE entries we have to fake them.
351                  */
352                 if (fsp) {
353                         is_directory = fsp->is_directory;
354                         psbuf = &fsp->fsp_name->st;
355                 } else {
356                         if (vfs_stat_smb_fname(handle->conn,
357                                                 name,
358                                                 &sbuf) == 0) {
359                                 is_directory = S_ISDIR(sbuf.st_ex_mode);
360                         }
361                 }
362                 if (is_directory &&
363                                 !sd_has_inheritable_components(psd,
364                                                         true)) {
365                         add_directory_inheritable_components(handle,
366                                                         name,
367                                                         psbuf,
368                                                         psd);
369                 }
370         }
371
372         if (!(security_info & OWNER_SECURITY_INFORMATION)) {
373                 psd->owner_sid = NULL;
374         }
375         if (!(security_info & GROUP_SECURITY_INFORMATION)) {
376                 psd->group_sid = NULL;
377         }
378         if (!(security_info & DACL_SECURITY_INFORMATION)) {
379                 psd->dacl = NULL;
380         }
381         if (!(security_info & SACL_SECURITY_INFORMATION)) {
382                 psd->sacl = NULL;
383         }
384
385         TALLOC_FREE(blob.data);
386         *ppdesc = psd;
387         return NT_STATUS_OK;
388 }
389
390 /*********************************************************************
391  Create a default ACL by inheriting from the parent. If no inheritance
392  from the parent available, don't set anything. This will leave the actual
393  permissions the new file or directory already got from the filesystem
394  as the NT ACL when read.
395 *********************************************************************/
396
397 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
398                                         files_struct *fsp,
399                                         struct security_descriptor *parent_desc,
400                                         bool is_directory)
401 {
402         TALLOC_CTX *ctx = talloc_tos();
403         NTSTATUS status = NT_STATUS_OK;
404         struct security_descriptor *psd = NULL;
405         size_t size;
406
407         if (!sd_has_inheritable_components(parent_desc, is_directory)) {
408                 return NT_STATUS_OK;
409         }
410
411         /* Create an inherited descriptor from the parent. */
412
413         if (DEBUGLEVEL >= 10) {
414                 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
415                         fsp_str_dbg(fsp) ));
416                 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
417         }
418
419         status = se_create_child_secdesc(ctx,
420                         &psd,
421                         &size,
422                         parent_desc,
423                         &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX],
424                         &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX],
425                         is_directory);
426         if (!NT_STATUS_IS_OK(status)) {
427                 return status;
428         }
429
430         if (DEBUGLEVEL >= 10) {
431                 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
432                         fsp_str_dbg(fsp) ));
433                 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
434         }
435
436         return SMB_VFS_FSET_NT_ACL(fsp,
437                                 (OWNER_SECURITY_INFORMATION |
438                                  GROUP_SECURITY_INFORMATION |
439                                  DACL_SECURITY_INFORMATION),
440                                 psd);
441 }
442
443 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
444                                 const char *path,
445                                 uint32_t access_mask,
446                                 struct security_descriptor **pp_parent_desc)
447 {
448         char *parent_name = NULL;
449         struct security_descriptor *parent_desc = NULL;
450         uint32_t access_granted = 0;
451         NTSTATUS status;
452
453         if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
454                 return NT_STATUS_NO_MEMORY;
455         }
456
457         status = get_nt_acl_internal(handle,
458                                         NULL,
459                                         parent_name,
460                                         (OWNER_SECURITY_INFORMATION |
461                                          GROUP_SECURITY_INFORMATION |
462                                          DACL_SECURITY_INFORMATION),
463                                         &parent_desc);
464
465         if (!NT_STATUS_IS_OK(status)) {
466                 DEBUG(10,("check_parent_acl_common: get_nt_acl_internal "
467                         "on directory %s for "
468                         "path %s returned %s\n",
469                         parent_name,
470                         path,
471                         nt_errstr(status) ));
472                 return status;
473         }
474         if (pp_parent_desc) {
475                 *pp_parent_desc = parent_desc;
476         }
477         status = smb1_file_se_access_check(handle->conn,
478                                         parent_desc,
479                                         get_current_nttok(handle->conn),
480                                         access_mask,
481                                         &access_granted);
482         if(!NT_STATUS_IS_OK(status)) {
483                 DEBUG(10,("check_parent_acl_common: access check "
484                         "on directory %s for "
485                         "path %s for mask 0x%x returned %s\n",
486                         parent_name,
487                         path,
488                         access_mask,
489                         nt_errstr(status) ));
490                 return status;
491         }
492         return NT_STATUS_OK;
493 }
494
495 static void free_sd_common(void **ptr)
496 {
497         TALLOC_FREE(*ptr);
498 }
499
500 /*********************************************************************
501  Check ACL on open. For new files inherit from parent directory.
502 *********************************************************************/
503
504 static int open_acl_common(vfs_handle_struct *handle,
505                         struct smb_filename *smb_fname,
506                         files_struct *fsp,
507                         int flags,
508                         mode_t mode)
509 {
510         uint32_t access_granted = 0;
511         struct security_descriptor *pdesc = NULL;
512         struct security_descriptor *parent_desc = NULL;
513         bool file_existed = true;
514         char *fname = NULL;
515         NTSTATUS status;
516
517         if (fsp->base_fsp) {
518                 /* Stream open. Base filename open already did the ACL check. */
519                 DEBUG(10,("open_acl_common: stream open on %s\n",
520                         fsp_str_dbg(fsp) ));
521                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
522         }
523
524         status = get_full_smb_filename(talloc_tos(), smb_fname,
525                                        &fname);
526         if (!NT_STATUS_IS_OK(status)) {
527                 goto err;
528         }
529
530         status = get_nt_acl_internal(handle,
531                                 NULL,
532                                 fname,
533                                 (OWNER_SECURITY_INFORMATION |
534                                  GROUP_SECURITY_INFORMATION |
535                                  DACL_SECURITY_INFORMATION),
536                                 &pdesc);
537         if (NT_STATUS_IS_OK(status)) {
538                 /* See if we can access it. */
539                 status = smb1_file_se_access_check(handle->conn,
540                                         pdesc,
541                                         get_current_nttok(handle->conn),
542                                         fsp->access_mask,
543                                         &access_granted);
544                 if (!NT_STATUS_IS_OK(status)) {
545                         DEBUG(10,("open_acl_xattr: %s open "
546                                 "refused with error %s\n",
547                                 fsp_str_dbg(fsp),
548                                 nt_errstr(status) ));
549                         goto err;
550                 }
551         } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
552                 file_existed = false;
553                 /*
554                  * If O_CREAT is true then we're trying to create a file.
555                  * Check the parent directory ACL will allow this.
556                  */
557                 if (flags & O_CREAT) {
558                         struct security_descriptor *psd = NULL;
559
560                         status = check_parent_acl_common(handle, fname,
561                                         SEC_DIR_ADD_FILE, &parent_desc);
562                         if (!NT_STATUS_IS_OK(status)) {
563                                 goto err;
564                         }
565                         /* Cache the parent security descriptor for
566                          * later use. We do have an fsp here, but to
567                          * keep the code consistent with the directory
568                          * case which doesn't, use the handle. */
569
570                         /* Attach this to the conn, move from talloc_tos(). */
571                         psd = (struct security_descriptor *)talloc_move(handle->conn,
572                                 &parent_desc);
573
574                         if (!psd) {
575                                 status = NT_STATUS_NO_MEMORY;
576                                 goto err;
577                         }
578                         status = NT_STATUS_NO_MEMORY;
579                         SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
580                                 struct security_descriptor *, goto err);
581                         status = NT_STATUS_OK;
582                 }
583         }
584
585         DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
586                 "%s returned %s\n",
587                 fsp_str_dbg(fsp),
588                 nt_errstr(status) ));
589
590         fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
591         return fsp->fh->fd;
592
593   err:
594
595         errno = map_errno_from_nt_status(status);
596         return -1;
597 }
598
599 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
600 {
601         int ret;
602         NTSTATUS status;
603         SMB_STRUCT_STAT sbuf;
604
605         ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
606         if (ret == -1 && errno == ENOENT) {
607                 struct security_descriptor *parent_desc = NULL;
608                 struct security_descriptor *psd = NULL;
609
610                 /* We're creating a new directory. */
611                 status = check_parent_acl_common(handle, path,
612                                 SEC_DIR_ADD_SUBDIR, &parent_desc);
613                 if (!NT_STATUS_IS_OK(status)) {
614                         errno = map_errno_from_nt_status(status);
615                         return -1;
616                 }
617
618                 /* Cache the parent security descriptor for
619                  * later use. We don't have an fsp here so
620                  * use the handle. */
621
622                 /* Attach this to the conn, move from talloc_tos(). */
623                 psd = (struct security_descriptor *)talloc_move(handle->conn,
624                                 &parent_desc);
625
626                 if (!psd) {
627                         return -1;
628                 }
629                 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
630                         struct security_descriptor *, return -1);
631         }
632
633         return SMB_VFS_NEXT_MKDIR(handle, path, mode);
634 }
635
636 /*********************************************************************
637  Fetch a security descriptor given an fsp.
638 *********************************************************************/
639
640 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
641         uint32_t security_info, struct security_descriptor **ppdesc)
642 {
643         return get_nt_acl_internal(handle, fsp,
644                                 NULL, security_info, ppdesc);
645 }
646
647 /*********************************************************************
648  Fetch a security descriptor given a pathname.
649 *********************************************************************/
650
651 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
652         const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
653 {
654         return get_nt_acl_internal(handle, NULL,
655                                 name, security_info, ppdesc);
656 }
657
658 /*********************************************************************
659  Store a security descriptor given an fsp.
660 *********************************************************************/
661
662 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
663         uint32_t security_info_sent, const struct security_descriptor *psd)
664 {
665         NTSTATUS status;
666         DATA_BLOB blob;
667         struct security_descriptor *pdesc_next = NULL;
668         uint8_t hash[XATTR_SD_HASH_SIZE];
669
670         if (DEBUGLEVEL >= 10) {
671                 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
672                           fsp_str_dbg(fsp)));
673                 NDR_PRINT_DEBUG(security_descriptor,
674                         CONST_DISCARD(struct security_descriptor *,psd));
675         }
676
677         /* Ensure we have OWNER/GROUP/DACL set. */
678
679         if ((security_info_sent & (OWNER_SECURITY_INFORMATION|
680                                 GROUP_SECURITY_INFORMATION|
681                                 DACL_SECURITY_INFORMATION)) !=
682                                 (OWNER_SECURITY_INFORMATION|
683                                  GROUP_SECURITY_INFORMATION|
684                                  DACL_SECURITY_INFORMATION)) {
685                 /* No we don't - read from the existing SD. */
686                 struct security_descriptor *nc_psd = NULL;
687
688                 status = get_nt_acl_internal(handle, fsp,
689                                 NULL,
690                                 (OWNER_SECURITY_INFORMATION|
691                                  GROUP_SECURITY_INFORMATION|
692                                  DACL_SECURITY_INFORMATION),
693                                 &nc_psd);
694
695                 if (!NT_STATUS_IS_OK(status)) {
696                         return status;
697                 }
698
699                 /* This is safe as nc_psd is discarded at fn exit. */
700                 if (security_info_sent & OWNER_SECURITY_INFORMATION) {
701                         nc_psd->owner_sid = psd->owner_sid;
702                 }
703                 security_info_sent |= OWNER_SECURITY_INFORMATION;
704
705                 if (security_info_sent & GROUP_SECURITY_INFORMATION) {
706                         nc_psd->group_sid = psd->group_sid;
707                 }
708                 security_info_sent |= GROUP_SECURITY_INFORMATION;
709
710                 if (security_info_sent & DACL_SECURITY_INFORMATION) {
711                         nc_psd->dacl = dup_sec_acl(talloc_tos(), psd->dacl);
712                         if (nc_psd->dacl == NULL) {
713                                 return NT_STATUS_NO_MEMORY;
714                         }
715                 }
716                 security_info_sent |= DACL_SECURITY_INFORMATION;
717                 psd = nc_psd;
718         }
719
720         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
721         if (!NT_STATUS_IS_OK(status)) {
722                 return status;
723         }
724
725         /* Get the full underlying sd, then hash. */
726         status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
727                                 fsp,
728                                 HASH_SECURITY_INFO,
729                                 &pdesc_next);
730
731         if (!NT_STATUS_IS_OK(status)) {
732                 return status;
733         }
734
735         status = hash_sd_sha256(pdesc_next, hash);
736         if (!NT_STATUS_IS_OK(status)) {
737                 return status;
738         }
739
740         if (DEBUGLEVEL >= 10) {
741                 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
742                           fsp_str_dbg(fsp)));
743                 NDR_PRINT_DEBUG(security_descriptor,
744                         CONST_DISCARD(struct security_descriptor *,psd));
745         }
746         create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
747         store_acl_blob_fsp(handle, fsp, &blob);
748
749         return NT_STATUS_OK;
750 }
751
752 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
753                         const char *fname, const char *mask, uint32 attr)
754 {
755         NTSTATUS status = check_parent_acl_common(handle, fname,
756                                         SEC_DIR_LIST, NULL);
757
758         if (!NT_STATUS_IS_OK(status)) {
759                 errno = map_errno_from_nt_status(status);
760                 return NULL;
761         }
762         return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
763 }
764
765 static int acl_common_remove_object(vfs_handle_struct *handle,
766                                         const char *path,
767                                         bool is_directory)
768 {
769         connection_struct *conn = handle->conn;
770         struct file_id id;
771         files_struct *fsp = NULL;
772         int ret = 0;
773         char *parent_dir = NULL;
774         const char *final_component = NULL;
775         struct smb_filename local_fname;
776         int saved_errno = 0;
777
778         if (!parent_dirname(talloc_tos(), path,
779                         &parent_dir, &final_component)) {
780                 saved_errno = ENOMEM;
781                 goto out;
782         }
783
784         DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
785                 is_directory ? "directory" : "file",
786                 parent_dir, final_component ));
787
788         /* cd into the parent dir to pin it. */
789         ret = SMB_VFS_CHDIR(conn, parent_dir);
790         if (ret == -1) {
791                 saved_errno = errno;
792                 goto out;
793         }
794
795         ZERO_STRUCT(local_fname);
796         local_fname.base_name = CONST_DISCARD(char *,final_component);
797
798         /* Must use lstat here. */
799         ret = SMB_VFS_LSTAT(conn, &local_fname);
800         if (ret == -1) {
801                 saved_errno = errno;
802                 goto out;
803         }
804
805         /* Ensure we have this file open with DELETE access. */
806         id = vfs_file_id_from_sbuf(conn, &local_fname.st);
807         for (fsp = file_find_di_first(id); fsp; file_find_di_next(fsp)) {
808                 if (fsp->access_mask & DELETE_ACCESS &&
809                                 fsp->delete_on_close) {
810                         /* We did open this for delete,
811                          * allow the delete as root.
812                          */
813                         break;
814                 }
815         }
816
817         if (!fsp) {
818                 DEBUG(10,("acl_common_remove_object: %s %s/%s "
819                         "not an open file\n",
820                         is_directory ? "directory" : "file",
821                         parent_dir, final_component ));
822                 saved_errno = EACCES;
823                 goto out;
824         }
825
826         become_root();
827         if (is_directory) {
828                 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
829         } else {
830                 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
831         }
832         unbecome_root();
833
834         if (ret == -1) {
835                 saved_errno = errno;
836         }
837
838   out:
839
840         TALLOC_FREE(parent_dir);
841
842         vfs_ChDir(conn, conn->connectpath);
843         if (saved_errno) {
844                 errno = saved_errno;
845         }
846         return ret;
847 }
848
849 static int rmdir_acl_common(struct vfs_handle_struct *handle,
850                                 const char *path)
851 {
852         int ret;
853
854         ret = SMB_VFS_NEXT_RMDIR(handle, path);
855         if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
856                 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
857                         path,
858                         strerror(errno) ));
859                 return ret;
860         }
861
862         return acl_common_remove_object(handle,
863                                         path,
864                                         true);
865 }
866
867 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
868                                 struct smb_request *req,
869                                 uint16_t root_dir_fid,
870                                 struct smb_filename *smb_fname,
871                                 uint32_t access_mask,
872                                 uint32_t share_access,
873                                 uint32_t create_disposition,
874                                 uint32_t create_options,
875                                 uint32_t file_attributes,
876                                 uint32_t oplock_request,
877                                 uint64_t allocation_size,
878                                 uint32_t private_flags,
879                                 struct security_descriptor *sd,
880                                 struct ea_list *ea_list,
881                                 files_struct **result,
882                                 int *pinfo)
883 {
884         NTSTATUS status, status1;
885         files_struct *fsp = NULL;
886         int info;
887         struct security_descriptor *parent_sd = NULL;
888
889         status = SMB_VFS_NEXT_CREATE_FILE(handle,
890                                         req,
891                                         root_dir_fid,
892                                         smb_fname,
893                                         access_mask,
894                                         share_access,
895                                         create_disposition,
896                                         create_options,
897                                         file_attributes,
898                                         oplock_request,
899                                         allocation_size,
900                                         private_flags,
901                                         sd,
902                                         ea_list,
903                                         result,
904                                         &info);
905
906         if (info != FILE_WAS_CREATED) {
907                 /* File/directory was opened, not created. */
908                 goto out;
909         }
910
911         fsp = *result;
912
913         if (!NT_STATUS_IS_OK(status) || fsp == NULL) {
914                 /* Only handle success. */
915                 goto out;
916         }
917
918         if (sd) {
919                 /* Security descriptor already set. */
920                 goto out;
921         }
922
923         if (fsp->base_fsp) {
924                 /* Stream open. */
925                 goto out;
926         }
927
928
929         /* We must have a cached parent sd in this case.
930          * attached to the handle. */
931
932         SMB_VFS_HANDLE_GET_DATA(handle, parent_sd,
933                 struct security_descriptor,
934                 goto err);
935
936         if (!parent_sd) {
937                 goto err;
938         }
939
940         /* New directory - inherit from parent. */
941         status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
942
943         if (!NT_STATUS_IS_OK(status1)) {
944                 DEBUG(1,("create_file_acl_common: error setting "
945                         "sd for %s (%s)\n",
946                         fsp_str_dbg(fsp),
947                         nt_errstr(status1) ));
948         }
949
950   out:
951
952         /* Ensure we never leave attached data around. */
953         SMB_VFS_HANDLE_FREE_DATA(handle);
954
955         if (NT_STATUS_IS_OK(status) && pinfo) {
956                 *pinfo = info;
957         }
958         return status;
959
960   err:
961
962         smb_panic("create_file_acl_common: logic error.\n");
963         /* NOTREACHED */
964         return status;
965 }
966
967 static int unlink_acl_common(struct vfs_handle_struct *handle,
968                         const struct smb_filename *smb_fname)
969 {
970         int ret;
971
972         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
973         if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
974                 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
975                         smb_fname->base_name,
976                         strerror(errno) ));
977                 return ret;
978         }
979         /* Don't do anything fancy for streams. */
980         if (smb_fname->stream_name) {
981                 return ret;
982         }
983
984         return acl_common_remove_object(handle,
985                                         smb_fname->base_name,
986                                         false);
987 }