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