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