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