s4:dsdb: Fix stack use after scope in gkdi_create_root_key()
[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 = discard_const_p(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 = discard_const_p(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         struct dom_sid *owner_sid = NULL;
450         struct dom_sid *group_sid = NULL;
451         bool inherit_owner = lp_inherit_owner(SNUM(handle->conn));
452         size_t size;
453
454         if (!sd_has_inheritable_components(parent_desc, is_directory)) {
455                 return NT_STATUS_OK;
456         }
457
458         /* Create an inherited descriptor from the parent. */
459
460         if (DEBUGLEVEL >= 10) {
461                 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
462                         fsp_str_dbg(fsp) ));
463                 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
464         }
465
466         /* Inherit from parent descriptor if "inherit owner" set. */
467         if (inherit_owner) {
468                 owner_sid = parent_desc->owner_sid;
469                 group_sid = parent_desc->group_sid;
470         }
471
472         if (owner_sid == NULL) {
473                 owner_sid = &handle->conn->session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
474         }
475         if (group_sid == NULL) {
476                 group_sid = &handle->conn->session_info->security_token->sids[PRIMARY_GROUP_SID_INDEX];
477         }
478
479         status = se_create_child_secdesc(ctx,
480                         &psd,
481                         &size,
482                         parent_desc,
483                         owner_sid,
484                         group_sid,
485                         is_directory);
486         if (!NT_STATUS_IS_OK(status)) {
487                 return status;
488         }
489
490         if (DEBUGLEVEL >= 10) {
491                 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
492                         fsp_str_dbg(fsp) ));
493                 NDR_PRINT_DEBUG(security_descriptor, psd);
494         }
495
496         if (inherit_owner) {
497                 /* We need to be root to force this. */
498                 become_root();
499         }
500         status = SMB_VFS_FSET_NT_ACL(fsp,
501                                 (SECINFO_OWNER |
502                                  SECINFO_GROUP |
503                                  SECINFO_DACL),
504                                 psd);
505         if (inherit_owner) {
506                 unbecome_root();
507         }
508         return status;
509 }
510
511 static NTSTATUS get_parent_acl_common(vfs_handle_struct *handle,
512                                 const char *path,
513                                 struct security_descriptor **pp_parent_desc)
514 {
515         char *parent_name = NULL;
516         NTSTATUS status;
517
518         if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
519                 return NT_STATUS_NO_MEMORY;
520         }
521
522         status = get_nt_acl_internal(handle,
523                                         NULL,
524                                         parent_name,
525                                         (SECINFO_OWNER |
526                                          SECINFO_GROUP |
527                                          SECINFO_DACL),
528                                         pp_parent_desc);
529
530         if (!NT_STATUS_IS_OK(status)) {
531                 DEBUG(10,("get_parent_acl_common: get_nt_acl_internal "
532                         "on directory %s for "
533                         "path %s returned %s\n",
534                         parent_name,
535                         path,
536                         nt_errstr(status) ));
537         }
538         return status;
539 }
540
541 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
542                                 const char *path,
543                                 uint32_t access_mask,
544                                 struct security_descriptor **pp_parent_desc)
545 {
546         char *parent_name = NULL;
547         struct security_descriptor *parent_desc = NULL;
548         uint32_t access_granted = 0;
549         NTSTATUS status;
550
551         status = get_parent_acl_common(handle, path, &parent_desc);
552         if (!NT_STATUS_IS_OK(status)) {
553                 return status;
554         }
555         if (pp_parent_desc) {
556                 *pp_parent_desc = parent_desc;
557         }
558         status = smb1_file_se_access_check(handle->conn,
559                                         parent_desc,
560                                         get_current_nttok(handle->conn),
561                                         access_mask,
562                                         &access_granted);
563         if(!NT_STATUS_IS_OK(status)) {
564                 DEBUG(10,("check_parent_acl_common: access check "
565                         "on directory %s for "
566                         "path %s for mask 0x%x returned %s\n",
567                         parent_name,
568                         path,
569                         access_mask,
570                         nt_errstr(status) ));
571                 return status;
572         }
573         return NT_STATUS_OK;
574 }
575
576 /*********************************************************************
577  Check ACL on open. For new files inherit from parent directory.
578 *********************************************************************/
579
580 static int open_acl_common(vfs_handle_struct *handle,
581                         struct smb_filename *smb_fname,
582                         files_struct *fsp,
583                         int flags,
584                         mode_t mode)
585 {
586         uint32_t access_granted = 0;
587         struct security_descriptor *pdesc = NULL;
588         bool file_existed = true;
589         char *fname = NULL;
590         NTSTATUS status;
591
592         if (fsp->base_fsp) {
593                 /* Stream open. Base filename open already did the ACL check. */
594                 DEBUG(10,("open_acl_common: stream open on %s\n",
595                         fsp_str_dbg(fsp) ));
596                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
597         }
598
599         status = get_full_smb_filename(talloc_tos(), smb_fname,
600                                        &fname);
601         if (!NT_STATUS_IS_OK(status)) {
602                 goto err;
603         }
604
605         status = get_nt_acl_internal(handle,
606                                 NULL,
607                                 fname,
608                                 (SECINFO_OWNER |
609                                  SECINFO_GROUP |
610                                  SECINFO_DACL),
611                                 &pdesc);
612         if (NT_STATUS_IS_OK(status)) {
613                 /* See if we can access it. */
614                 status = smb1_file_se_access_check(handle->conn,
615                                         pdesc,
616                                         get_current_nttok(handle->conn),
617                                         fsp->access_mask,
618                                         &access_granted);
619                 if (!NT_STATUS_IS_OK(status)) {
620                         DEBUG(10,("open_acl_xattr: %s open "
621                                 "refused with error %s\n",
622                                 fsp_str_dbg(fsp),
623                                 nt_errstr(status) ));
624                         goto err;
625                 }
626         } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
627                 file_existed = false;
628                 /*
629                  * If O_CREAT is true then we're trying to create a file.
630                  * Check the parent directory ACL will allow this.
631                  */
632                 if (flags & O_CREAT) {
633                         struct security_descriptor *parent_desc = NULL;
634                         struct security_descriptor **pp_psd = NULL;
635
636                         status = check_parent_acl_common(handle, fname,
637                                         SEC_DIR_ADD_FILE, &parent_desc);
638                         if (!NT_STATUS_IS_OK(status)) {
639                                 goto err;
640                         }
641
642                         /* Cache the parent security descriptor for
643                          * later use. */
644
645                         pp_psd = VFS_ADD_FSP_EXTENSION(handle,
646                                         fsp,
647                                         struct security_descriptor *,
648                                         NULL);
649                         if (!pp_psd) {
650                                 status = NT_STATUS_NO_MEMORY;
651                                 goto err;
652                         }
653
654                         *pp_psd = parent_desc;
655                         status = NT_STATUS_OK;
656                 }
657         }
658
659         DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
660                 "%s returned %s\n",
661                 fsp_str_dbg(fsp),
662                 nt_errstr(status) ));
663
664         fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
665         return fsp->fh->fd;
666
667   err:
668
669         errno = map_errno_from_nt_status(status);
670         return -1;
671 }
672
673 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
674 {
675         int ret;
676         NTSTATUS status;
677         SMB_STRUCT_STAT sbuf;
678
679         ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
680         if (ret == -1 && errno == ENOENT) {
681                 /* We're creating a new directory. */
682                 status = check_parent_acl_common(handle, path,
683                                 SEC_DIR_ADD_SUBDIR, NULL);
684                 if (!NT_STATUS_IS_OK(status)) {
685                         errno = map_errno_from_nt_status(status);
686                         return -1;
687                 }
688         }
689
690         return SMB_VFS_NEXT_MKDIR(handle, path, mode);
691 }
692
693 /*********************************************************************
694  Fetch a security descriptor given an fsp.
695 *********************************************************************/
696
697 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
698         uint32_t security_info, struct security_descriptor **ppdesc)
699 {
700         return get_nt_acl_internal(handle, fsp,
701                                 NULL, security_info, ppdesc);
702 }
703
704 /*********************************************************************
705  Fetch a security descriptor given a pathname.
706 *********************************************************************/
707
708 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
709         const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
710 {
711         return get_nt_acl_internal(handle, NULL,
712                                 name, security_info, ppdesc);
713 }
714
715 /*********************************************************************
716  Store a security descriptor given an fsp.
717 *********************************************************************/
718
719 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
720         uint32_t security_info_sent, const struct security_descriptor *orig_psd)
721 {
722         NTSTATUS status;
723         DATA_BLOB blob;
724         struct security_descriptor *pdesc_next = NULL;
725         struct security_descriptor *psd = NULL;
726         uint8_t hash[XATTR_SD_HASH_SIZE];
727
728         if (DEBUGLEVEL >= 10) {
729                 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
730                           fsp_str_dbg(fsp)));
731                 NDR_PRINT_DEBUG(security_descriptor,
732                         discard_const_p(struct security_descriptor, orig_psd));
733         }
734
735         status = get_nt_acl_internal(handle, fsp,
736                         NULL,
737                         SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL,
738                         &psd);
739
740         if (!NT_STATUS_IS_OK(status)) {
741                 return status;
742         }
743
744         psd->revision = orig_psd->revision;
745         /* All our SD's are self relative. */
746         psd->type = orig_psd->type | SEC_DESC_SELF_RELATIVE;
747
748         if ((security_info_sent & SECINFO_OWNER) && (orig_psd->owner_sid != NULL)) {
749                 psd->owner_sid = orig_psd->owner_sid;
750         }
751         if ((security_info_sent & SECINFO_GROUP) && (orig_psd->group_sid != NULL)) {
752                 psd->group_sid = orig_psd->group_sid;
753         }
754         if (security_info_sent & SECINFO_DACL) {
755                 psd->dacl = orig_psd->dacl;
756                 psd->type |= SEC_DESC_DACL_PRESENT;
757         }
758         if (security_info_sent & SECINFO_SACL) {
759                 psd->sacl = orig_psd->sacl;
760                 psd->type |= SEC_DESC_SACL_PRESENT;
761         }
762
763         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
764         if (!NT_STATUS_IS_OK(status)) {
765                 return status;
766         }
767
768         /* Get the full underlying sd, then hash. */
769         status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
770                                 fsp,
771                                 HASH_SECURITY_INFO,
772                                 &pdesc_next);
773
774         if (!NT_STATUS_IS_OK(status)) {
775                 return status;
776         }
777
778         status = hash_sd_sha256(pdesc_next, hash);
779         if (!NT_STATUS_IS_OK(status)) {
780                 return status;
781         }
782
783         if (DEBUGLEVEL >= 10) {
784                 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
785                           fsp_str_dbg(fsp)));
786                 NDR_PRINT_DEBUG(security_descriptor,
787                         discard_const_p(struct security_descriptor, psd));
788         }
789         create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
790         store_acl_blob_fsp(handle, fsp, &blob);
791
792         return NT_STATUS_OK;
793 }
794
795 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
796                         const char *fname, const char *mask, uint32 attr)
797 {
798         NTSTATUS status = check_parent_acl_common(handle, fname,
799                                         SEC_DIR_LIST, NULL);
800
801         if (!NT_STATUS_IS_OK(status)) {
802                 errno = map_errno_from_nt_status(status);
803                 return NULL;
804         }
805         return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
806 }
807
808 static int acl_common_remove_object(vfs_handle_struct *handle,
809                                         const char *path,
810                                         bool is_directory)
811 {
812         connection_struct *conn = handle->conn;
813         struct file_id id;
814         files_struct *fsp = NULL;
815         int ret = 0;
816         char *parent_dir = NULL;
817         const char *final_component = NULL;
818         struct smb_filename local_fname;
819         int saved_errno = 0;
820
821         if (!parent_dirname(talloc_tos(), path,
822                         &parent_dir, &final_component)) {
823                 saved_errno = ENOMEM;
824                 goto out;
825         }
826
827         DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
828                 is_directory ? "directory" : "file",
829                 parent_dir, final_component ));
830
831         /* cd into the parent dir to pin it. */
832         ret = SMB_VFS_CHDIR(conn, parent_dir);
833         if (ret == -1) {
834                 saved_errno = errno;
835                 goto out;
836         }
837
838         ZERO_STRUCT(local_fname);
839         local_fname.base_name = discard_const_p(char, final_component);
840
841         /* Must use lstat here. */
842         ret = SMB_VFS_LSTAT(conn, &local_fname);
843         if (ret == -1) {
844                 saved_errno = errno;
845                 goto out;
846         }
847
848         /* Ensure we have this file open with DELETE access. */
849         id = vfs_file_id_from_sbuf(conn, &local_fname.st);
850         for (fsp = file_find_di_first(conn->sconn, id); fsp;
851              file_find_di_next(fsp)) {
852                 if (fsp->access_mask & DELETE_ACCESS &&
853                                 fsp->delete_on_close) {
854                         /* We did open this for delete,
855                          * allow the delete as root.
856                          */
857                         break;
858                 }
859         }
860
861         if (!fsp) {
862                 DEBUG(10,("acl_common_remove_object: %s %s/%s "
863                         "not an open file\n",
864                         is_directory ? "directory" : "file",
865                         parent_dir, final_component ));
866                 saved_errno = EACCES;
867                 goto out;
868         }
869
870         become_root();
871         if (is_directory) {
872                 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
873         } else {
874                 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
875         }
876         unbecome_root();
877
878         if (ret == -1) {
879                 saved_errno = errno;
880         }
881
882   out:
883
884         TALLOC_FREE(parent_dir);
885
886         vfs_ChDir(conn, conn->connectpath);
887         if (saved_errno) {
888                 errno = saved_errno;
889         }
890         return ret;
891 }
892
893 static int rmdir_acl_common(struct vfs_handle_struct *handle,
894                                 const char *path)
895 {
896         int ret;
897
898         ret = SMB_VFS_NEXT_RMDIR(handle, path);
899         if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
900                 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
901                         path,
902                         strerror(errno) ));
903                 return ret;
904         }
905
906         return acl_common_remove_object(handle,
907                                         path,
908                                         true);
909 }
910
911 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
912                                 struct smb_request *req,
913                                 uint16_t root_dir_fid,
914                                 struct smb_filename *smb_fname,
915                                 uint32_t access_mask,
916                                 uint32_t share_access,
917                                 uint32_t create_disposition,
918                                 uint32_t create_options,
919                                 uint32_t file_attributes,
920                                 uint32_t oplock_request,
921                                 uint64_t allocation_size,
922                                 uint32_t private_flags,
923                                 struct security_descriptor *sd,
924                                 struct ea_list *ea_list,
925                                 files_struct **result,
926                                 int *pinfo)
927 {
928         NTSTATUS status, status1;
929         files_struct *fsp = NULL;
930         int info;
931         struct security_descriptor *parent_sd = NULL;
932         struct security_descriptor **pp_parent_sd = NULL;
933
934         status = SMB_VFS_NEXT_CREATE_FILE(handle,
935                                         req,
936                                         root_dir_fid,
937                                         smb_fname,
938                                         access_mask,
939                                         share_access,
940                                         create_disposition,
941                                         create_options,
942                                         file_attributes,
943                                         oplock_request,
944                                         allocation_size,
945                                         private_flags,
946                                         sd,
947                                         ea_list,
948                                         result,
949                                         &info);
950
951         if (!NT_STATUS_IS_OK(status)) {
952                 goto out;
953         }
954
955         if (info != FILE_WAS_CREATED) {
956                 /* File/directory was opened, not created. */
957                 goto out;
958         }
959
960         fsp = *result;
961
962         if (fsp == NULL) {
963                 /* Only handle success. */
964                 goto out;
965         }
966
967         if (sd) {
968                 /* Security descriptor already set. */
969                 goto out;
970         }
971
972         if (fsp->base_fsp) {
973                 /* Stream open. */
974                 goto out;
975         }
976
977         /* See if we have a cached parent sd, if so, use it. */
978         pp_parent_sd = (struct security_descriptor **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
979         if (!pp_parent_sd) {
980                 /* Must be a directory, fetch again (sigh). */
981                 status = get_parent_acl_common(handle,
982                                 fsp->fsp_name->base_name,
983                                 &parent_sd);
984                 if (!NT_STATUS_IS_OK(status)) {
985                         goto out;
986                 }
987         } else {
988                 parent_sd = *pp_parent_sd;
989         }
990
991         if (!parent_sd) {
992                 goto err;
993         }
994
995         /* New directory - inherit from parent. */
996         status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
997
998         if (!NT_STATUS_IS_OK(status1)) {
999                 DEBUG(1,("create_file_acl_common: error setting "
1000                         "sd for %s (%s)\n",
1001                         fsp_str_dbg(fsp),
1002                         nt_errstr(status1) ));
1003         }
1004
1005   out:
1006
1007         if (fsp) {
1008                 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
1009         }
1010
1011         if (NT_STATUS_IS_OK(status) && pinfo) {
1012                 *pinfo = info;
1013         }
1014         return status;
1015
1016   err:
1017
1018         smb_panic("create_file_acl_common: logic error.\n");
1019         /* NOTREACHED */
1020         return status;
1021 }
1022
1023 static int unlink_acl_common(struct vfs_handle_struct *handle,
1024                         const struct smb_filename *smb_fname)
1025 {
1026         int ret;
1027
1028         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1029         if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
1030                 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
1031                         smb_fname->base_name,
1032                         strerror(errno) ));
1033                 return ret;
1034         }
1035         /* Don't do anything fancy for streams. */
1036         if (smb_fname->stream_name) {
1037                 return ret;
1038         }
1039
1040         return acl_common_remove_object(handle,
1041                                         smb_fname->base_name,
1042                                         false);
1043 }
1044
1045 static int chmod_acl_module_common(struct vfs_handle_struct *handle,
1046                         const char *path, mode_t mode)
1047 {
1048         if (lp_posix_pathnames()) {
1049                 /* Only allow this on POSIX pathnames. */
1050                 return SMB_VFS_NEXT_CHMOD(handle, path, mode);
1051         }
1052         return 0;
1053 }
1054
1055 static int fchmod_acl_module_common(struct vfs_handle_struct *handle,
1056                         struct files_struct *fsp, mode_t mode)
1057 {
1058         if (fsp->posix_open) {
1059                 /* Only allow this on POSIX opens. */
1060                 return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
1061         }
1062         return 0;
1063 }
1064
1065 static int chmod_acl_acl_module_common(struct vfs_handle_struct *handle,
1066                         const char *name, mode_t mode)
1067 {
1068         if (lp_posix_pathnames()) {
1069                 /* Only allow this on POSIX pathnames. */
1070                 return SMB_VFS_NEXT_CHMOD_ACL(handle, name, mode);
1071         }
1072         return 0;
1073 }
1074
1075 static int fchmod_acl_acl_module_common(struct vfs_handle_struct *handle,
1076                         struct files_struct *fsp, mode_t mode)
1077 {
1078         if (fsp->posix_open) {
1079                 /* Only allow this on POSIX opens. */
1080                 return SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
1081         }
1082         return 0;
1083 }