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