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