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