s3: fix build issue on Tru64
[sfrench/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, NULL, &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, NULL, &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         status = smb1_file_se_access_check(parent_desc,
475                                         handle->conn->server_info->ptok,
476                                         access_mask,
477                                         &access_granted);
478         if(!NT_STATUS_IS_OK(status)) {
479                 DEBUG(10,("check_parent_acl_common: access check "
480                         "on directory %s for "
481                         "path %s for mask 0x%x returned %s\n",
482                         parent_name,
483                         path,
484                         access_mask,
485                         nt_errstr(status) ));
486                 return status;
487         }
488         if (pp_parent_desc) {
489                 *pp_parent_desc = parent_desc;
490         }
491         return NT_STATUS_OK;
492 }
493
494 static void free_sd_common(void **ptr)
495 {
496         TALLOC_FREE(*ptr);
497 }
498
499 /*********************************************************************
500  Check ACL on open. For new files inherit from parent directory.
501 *********************************************************************/
502
503 static int open_acl_common(vfs_handle_struct *handle,
504                         struct smb_filename *smb_fname,
505                         files_struct *fsp,
506                         int flags,
507                         mode_t mode)
508 {
509         uint32_t access_granted = 0;
510         struct security_descriptor *pdesc = NULL;
511         struct security_descriptor *parent_desc = NULL;
512         bool file_existed = true;
513         char *fname = NULL;
514         NTSTATUS status;
515
516         if (fsp->base_fsp) {
517                 /* Stream open. Base filename open already did the ACL check. */
518                 DEBUG(10,("open_acl_common: stream open on %s\n",
519                         fsp_str_dbg(fsp) ));
520                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
521         }
522
523         status = get_full_smb_filename(talloc_tos(), smb_fname,
524                                        &fname);
525         if (!NT_STATUS_IS_OK(status)) {
526                 goto err;
527         }
528
529         status = get_nt_acl_internal(handle,
530                                 NULL,
531                                 fname,
532                                 (OWNER_SECURITY_INFORMATION |
533                                  GROUP_SECURITY_INFORMATION |
534                                  DACL_SECURITY_INFORMATION),
535                                 &pdesc);
536         if (NT_STATUS_IS_OK(status)) {
537                 /* See if we can access it. */
538                 status = smb1_file_se_access_check(pdesc,
539                                         handle->conn->server_info->ptok,
540                                         fsp->access_mask,
541                                         &access_granted);
542                 if (!NT_STATUS_IS_OK(status)) {
543                         DEBUG(10,("open_acl_xattr: %s open "
544                                 "refused with error %s\n",
545                                 fsp_str_dbg(fsp),
546                                 nt_errstr(status) ));
547                         goto err;
548                 }
549         } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
550                 file_existed = false;
551                 /*
552                  * If O_CREAT is true then we're trying to create a file.
553                  * Check the parent directory ACL will allow this.
554                  */
555                 if (flags & O_CREAT) {
556                         struct security_descriptor *psd = NULL;
557
558                         status = check_parent_acl_common(handle, fname,
559                                         SEC_DIR_ADD_FILE, &parent_desc);
560                         if (!NT_STATUS_IS_OK(status)) {
561                                 goto err;
562                         }
563                         /* Cache the parent security descriptor for
564                          * later use. We do have an fsp here, but to
565                          * keep the code consistent with the directory
566                          * case which doesn't, use the handle. */
567
568                         /* Attach this to the conn, move from talloc_tos(). */
569                         psd = (struct security_descriptor *)talloc_move(handle->conn,
570                                 &parent_desc);
571
572                         if (!psd) {
573                                 status = NT_STATUS_NO_MEMORY;
574                                 goto err;
575                         }
576                         status = NT_STATUS_NO_MEMORY;
577                         SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
578                                 struct security_descriptor *, goto err);
579                         status = NT_STATUS_OK;
580                 }
581         }
582
583         DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
584                 "%s returned %s\n",
585                 fsp_str_dbg(fsp),
586                 nt_errstr(status) ));
587
588         fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
589         return fsp->fh->fd;
590
591   err:
592
593         errno = map_errno_from_nt_status(status);
594         return -1;
595 }
596
597 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
598 {
599         int ret;
600         NTSTATUS status;
601         SMB_STRUCT_STAT sbuf;
602
603         ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
604         if (ret == -1 && errno == ENOENT) {
605                 struct security_descriptor *parent_desc = NULL;
606                 struct security_descriptor *psd = NULL;
607
608                 /* We're creating a new directory. */
609                 status = check_parent_acl_common(handle, path,
610                                 SEC_DIR_ADD_SUBDIR, &parent_desc);
611                 if (!NT_STATUS_IS_OK(status)) {
612                         errno = map_errno_from_nt_status(status);
613                         return -1;
614                 }
615
616                 /* Cache the parent security descriptor for
617                  * later use. We don't have an fsp here so
618                  * use the handle. */
619
620                 /* Attach this to the conn, move from talloc_tos(). */
621                 psd = (struct security_descriptor *)talloc_move(handle->conn,
622                                 &parent_desc);
623
624                 if (!psd) {
625                         return -1;
626                 }
627                 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
628                         struct security_descriptor *, return -1);
629         }
630
631         return SMB_VFS_NEXT_MKDIR(handle, path, mode);
632 }
633
634 /*********************************************************************
635  Fetch a security descriptor given an fsp.
636 *********************************************************************/
637
638 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
639         uint32_t security_info, struct security_descriptor **ppdesc)
640 {
641         return get_nt_acl_internal(handle, fsp,
642                                 NULL, security_info, ppdesc);
643 }
644
645 /*********************************************************************
646  Fetch a security descriptor given a pathname.
647 *********************************************************************/
648
649 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
650         const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
651 {
652         return get_nt_acl_internal(handle, NULL,
653                                 name, security_info, ppdesc);
654 }
655
656 /*********************************************************************
657  Store a security descriptor given an fsp.
658 *********************************************************************/
659
660 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
661         uint32_t security_info_sent, const struct security_descriptor *psd)
662 {
663         NTSTATUS status;
664         DATA_BLOB blob;
665         struct security_descriptor *pdesc_next = NULL;
666         uint8_t hash[XATTR_SD_HASH_SIZE];
667
668         if (DEBUGLEVEL >= 10) {
669                 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
670                           fsp_str_dbg(fsp)));
671                 NDR_PRINT_DEBUG(security_descriptor,
672                         CONST_DISCARD(struct security_descriptor *,psd));
673         }
674
675         /* Ensure we have OWNER/GROUP/DACL set. */
676
677         if ((security_info_sent & (OWNER_SECURITY_INFORMATION|
678                                 GROUP_SECURITY_INFORMATION|
679                                 DACL_SECURITY_INFORMATION)) !=
680                                 (OWNER_SECURITY_INFORMATION|
681                                  GROUP_SECURITY_INFORMATION|
682                                  DACL_SECURITY_INFORMATION)) {
683                 /* No we don't - read from the existing SD. */
684                 struct security_descriptor *nc_psd = NULL;
685
686                 status = get_nt_acl_internal(handle, fsp,
687                                 NULL,
688                                 (OWNER_SECURITY_INFORMATION|
689                                  GROUP_SECURITY_INFORMATION|
690                                  DACL_SECURITY_INFORMATION),
691                                 &nc_psd);
692
693                 if (!NT_STATUS_IS_OK(status)) {
694                         return status;
695                 }
696
697                 /* This is safe as nc_psd is discarded at fn exit. */
698                 if (security_info_sent & OWNER_SECURITY_INFORMATION) {
699                         nc_psd->owner_sid = psd->owner_sid;
700                 }
701                 security_info_sent |= OWNER_SECURITY_INFORMATION;
702
703                 if (security_info_sent & GROUP_SECURITY_INFORMATION) {
704                         nc_psd->group_sid = psd->group_sid;
705                 }
706                 security_info_sent |= GROUP_SECURITY_INFORMATION;
707
708                 if (security_info_sent & DACL_SECURITY_INFORMATION) {
709                         nc_psd->dacl = dup_sec_acl(talloc_tos(), psd->dacl);
710                         if (nc_psd->dacl == NULL) {
711                                 return NT_STATUS_NO_MEMORY;
712                         }
713                 }
714                 security_info_sent |= DACL_SECURITY_INFORMATION;
715                 psd = nc_psd;
716         }
717
718         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
719         if (!NT_STATUS_IS_OK(status)) {
720                 return status;
721         }
722
723         /* Get the full underlying sd, then hash. */
724         status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
725                                 fsp,
726                                 HASH_SECURITY_INFO,
727                                 &pdesc_next);
728
729         if (!NT_STATUS_IS_OK(status)) {
730                 return status;
731         }
732
733         status = hash_sd_sha256(pdesc_next, hash);
734         if (!NT_STATUS_IS_OK(status)) {
735                 return status;
736         }
737
738         if (DEBUGLEVEL >= 10) {
739                 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
740                           fsp_str_dbg(fsp)));
741                 NDR_PRINT_DEBUG(security_descriptor,
742                         CONST_DISCARD(struct security_descriptor *,psd));
743         }
744         create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
745         store_acl_blob_fsp(handle, fsp, &blob);
746
747         return NT_STATUS_OK;
748 }
749
750 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
751                         const char *fname, const char *mask, uint32 attr)
752 {
753         NTSTATUS status = check_parent_acl_common(handle, fname,
754                                         SEC_DIR_LIST, NULL);
755
756         if (!NT_STATUS_IS_OK(status)) {
757                 errno = map_errno_from_nt_status(status);
758                 return NULL;
759         }
760         return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
761 }
762
763 static int acl_common_remove_object(vfs_handle_struct *handle,
764                                         const char *path,
765                                         bool is_directory)
766 {
767         connection_struct *conn = handle->conn;
768         struct file_id id;
769         files_struct *fsp = NULL;
770         int ret = 0;
771         char *parent_dir = NULL;
772         const char *final_component = NULL;
773         struct smb_filename local_fname;
774         int saved_errno = 0;
775
776         if (!parent_dirname(talloc_tos(), path,
777                         &parent_dir, &final_component)) {
778                 saved_errno = ENOMEM;
779                 goto out;
780         }
781
782         DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
783                 is_directory ? "directory" : "file",
784                 parent_dir, final_component ));
785
786         /* cd into the parent dir to pin it. */
787         ret = SMB_VFS_CHDIR(conn, parent_dir);
788         if (ret == -1) {
789                 saved_errno = errno;
790                 goto out;
791         }
792
793         ZERO_STRUCT(local_fname);
794         local_fname.base_name = CONST_DISCARD(char *,final_component);
795
796         /* Must use lstat here. */
797         ret = SMB_VFS_LSTAT(conn, &local_fname);
798         if (ret == -1) {
799                 saved_errno = errno;
800                 goto out;
801         }
802
803         /* Ensure we have this file open with DELETE access. */
804         id = vfs_file_id_from_sbuf(conn, &local_fname.st);
805         for (fsp = file_find_di_first(id); fsp; file_find_di_next(fsp)) {
806                 if (fsp->access_mask & DELETE_ACCESS &&
807                                 fsp->delete_on_close) {
808                         /* We did open this for delete,
809                          * allow the delete as root.
810                          */
811                         break;
812                 }
813         }
814
815         if (!fsp) {
816                 DEBUG(10,("acl_common_remove_object: %s %s/%s "
817                         "not an open file\n",
818                         is_directory ? "directory" : "file",
819                         parent_dir, final_component ));
820                 saved_errno = EACCES;
821                 goto out;
822         }
823
824         become_root();
825         if (is_directory) {
826                 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
827         } else {
828                 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
829         }
830         unbecome_root();
831
832         if (ret == -1) {
833                 saved_errno = errno;
834         }
835
836   out:
837
838         TALLOC_FREE(parent_dir);
839
840         vfs_ChDir(conn, conn->connectpath);
841         if (saved_errno) {
842                 errno = saved_errno;
843         }
844         return ret;
845 }
846
847 static int rmdir_acl_common(struct vfs_handle_struct *handle,
848                                 const char *path)
849 {
850         int ret;
851
852         ret = SMB_VFS_NEXT_RMDIR(handle, path);
853         if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
854                 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
855                         path,
856                         strerror(errno) ));
857                 return ret;
858         }
859
860         return acl_common_remove_object(handle,
861                                         path,
862                                         true);
863 }
864
865 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
866                                 struct smb_request *req,
867                                 uint16_t root_dir_fid,
868                                 struct smb_filename *smb_fname,
869                                 uint32_t access_mask,
870                                 uint32_t share_access,
871                                 uint32_t create_disposition,
872                                 uint32_t create_options,
873                                 uint32_t file_attributes,
874                                 uint32_t oplock_request,
875                                 uint64_t allocation_size,
876                                 struct security_descriptor *sd,
877                                 struct ea_list *ea_list,
878                                 files_struct **result,
879                                 int *pinfo)
880 {
881         NTSTATUS status, status1;
882         files_struct *fsp = NULL;
883         int info;
884         struct security_descriptor *parent_sd = NULL;
885
886         status = SMB_VFS_NEXT_CREATE_FILE(handle,
887                                         req,
888                                         root_dir_fid,
889                                         smb_fname,
890                                         access_mask,
891                                         share_access,
892                                         create_disposition,
893                                         create_options,
894                                         file_attributes,
895                                         oplock_request,
896                                         allocation_size,
897                                         sd,
898                                         ea_list,
899                                         result,
900                                         &info);
901
902         if (info != FILE_WAS_CREATED) {
903                 /* File/directory was opened, not created. */
904                 goto out;
905         }
906
907         fsp = *result;
908
909         if (!NT_STATUS_IS_OK(status) || fsp == NULL) {
910                 /* Only handle success. */
911                 goto out;
912         }
913
914         if (sd) {
915                 /* Security descriptor already set. */
916                 goto out;
917         }
918
919         if (fsp->base_fsp) {
920                 /* Stream open. */
921                 goto out;
922         }
923
924
925         /* We must have a cached parent sd in this case.
926          * attached to the handle. */
927
928         SMB_VFS_HANDLE_GET_DATA(handle, parent_sd,
929                 struct security_descriptor,
930                 goto err);
931
932         if (!parent_sd) {
933                 goto err;
934         }
935
936         /* New directory - inherit from parent. */
937         status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
938
939         if (!NT_STATUS_IS_OK(status1)) {
940                 DEBUG(1,("create_file_acl_common: error setting "
941                         "sd for %s (%s)\n",
942                         fsp_str_dbg(fsp),
943                         nt_errstr(status1) ));
944         }
945
946   out:
947
948         /* Ensure we never leave attached data around. */
949         SMB_VFS_HANDLE_FREE_DATA(handle);
950
951         if (NT_STATUS_IS_OK(status) && pinfo) {
952                 *pinfo = info;
953         }
954         return status;
955
956   err:
957
958         smb_panic("create_file_acl_common: logic error.\n");
959         /* NOTREACHED */
960         return status;
961 }
962
963 static int unlink_acl_common(struct vfs_handle_struct *handle,
964                         const struct smb_filename *smb_fname)
965 {
966         int ret;
967
968         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
969         if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
970                 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
971                         smb_fname->base_name,
972                         strerror(errno) ));
973                 return ret;
974         }
975         /* Don't do anything fancy for streams. */
976         if (smb_fname->stream_name) {
977                 return ret;
978         }
979
980         return acl_common_remove_object(handle,
981                                         smb_fname->base_name,
982                                         false);
983 }