s3: Fix an uninitialized variable
[idra/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
260         if (fsp && name == NULL) {
261                 name = fsp->fsp_name->base_name;
262         }
263
264         DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));
265
266         /* Get the full underlying sd for the hash
267            or to return as backup. */
268         if (fsp) {
269                 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
270                                 fsp,
271                                 HASH_SECURITY_INFO,
272                                 &pdesc_next);
273         } else {
274                 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
275                                 name,
276                                 HASH_SECURITY_INFO,
277                                 &pdesc_next);
278         }
279
280         if (!NT_STATUS_IS_OK(status)) {
281                 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
282                         "returned %s\n",
283                         name,
284                         nt_errstr(status)));
285                 return status;
286         }
287
288         status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
289         if (!NT_STATUS_IS_OK(status)) {
290                 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
291                         nt_errstr(status)));
292                 psd = pdesc_next;
293                 goto out;
294         }
295
296         status = parse_acl_blob(&blob, &psd,
297                                 &hash_type, &hash[0]);
298         if (!NT_STATUS_IS_OK(status)) {
299                 DEBUG(10, ("parse_acl_blob returned %s\n",
300                                 nt_errstr(status)));
301                 psd = pdesc_next;
302                 goto out;
303         }
304
305         /* Ensure the hash type is one we know. */
306         switch (hash_type) {
307                 case XATTR_SD_HASH_TYPE_NONE:
308                         /* No hash, just return blob sd. */
309                         goto out;
310                 case XATTR_SD_HASH_TYPE_SHA256:
311                         break;
312                 default:
313                         DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
314                                 "mismatch (%u) for file %s\n",
315                                 (unsigned int)hash_type,
316                                 name));
317                         TALLOC_FREE(psd);
318                         psd = pdesc_next;
319                         goto out;
320         }
321
322
323         status = hash_sd_sha256(pdesc_next, hash_tmp);
324         if (!NT_STATUS_IS_OK(status)) {
325                 TALLOC_FREE(psd);
326                 psd = pdesc_next;
327                 goto out;
328         }
329
330         if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
331                 /* Hash matches, return blob sd. */
332                 goto out;
333         }
334
335         /* Hash doesn't match, return underlying sd. */
336         TALLOC_FREE(psd);
337         psd = pdesc_next;
338
339   out:
340
341         if (psd != pdesc_next) {
342                 /* We're returning the blob, throw
343                  * away the filesystem SD. */
344                 TALLOC_FREE(pdesc_next);
345         } else {
346                 SMB_STRUCT_STAT sbuf;
347                 SMB_STRUCT_STAT *psbuf = &sbuf;
348                 bool is_directory = false;
349                 /*
350                  * We're returning the underlying ACL from the
351                  * filesystem. If it's a directory, and has no
352                  * inheritable ACE entries we have to fake them.
353                  */
354                 if (fsp) {
355                         is_directory = fsp->is_directory;
356                         psbuf = &fsp->fsp_name->st;
357                 } else {
358                         if (vfs_stat_smb_fname(handle->conn,
359                                                 name,
360                                                 &sbuf) == 0) {
361                                 is_directory = S_ISDIR(sbuf.st_ex_mode);
362                         }
363                 }
364                 if (is_directory &&
365                                 !sd_has_inheritable_components(psd,
366                                                         true)) {
367                         add_directory_inheritable_components(handle,
368                                                         name,
369                                                         psbuf,
370                                                         psd);
371                 }
372         }
373
374         if (!(security_info & SECINFO_OWNER)) {
375                 psd->owner_sid = NULL;
376         }
377         if (!(security_info & SECINFO_GROUP)) {
378                 psd->group_sid = NULL;
379         }
380         if (!(security_info & SECINFO_DACL)) {
381                 psd->dacl = NULL;
382         }
383         if (!(security_info & SECINFO_SACL)) {
384                 psd->sacl = NULL;
385         }
386
387         TALLOC_FREE(blob.data);
388         *ppdesc = psd;
389         return NT_STATUS_OK;
390 }
391
392 /*********************************************************************
393  Create a default ACL by inheriting from the parent. If no inheritance
394  from the parent available, don't set anything. This will leave the actual
395  permissions the new file or directory already got from the filesystem
396  as the NT ACL when read.
397 *********************************************************************/
398
399 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
400                                         files_struct *fsp,
401                                         struct security_descriptor *parent_desc,
402                                         bool is_directory)
403 {
404         TALLOC_CTX *ctx = talloc_tos();
405         NTSTATUS status = NT_STATUS_OK;
406         struct security_descriptor *psd = NULL;
407         size_t size;
408
409         if (!sd_has_inheritable_components(parent_desc, is_directory)) {
410                 return NT_STATUS_OK;
411         }
412
413         /* Create an inherited descriptor from the parent. */
414
415         if (DEBUGLEVEL >= 10) {
416                 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
417                         fsp_str_dbg(fsp) ));
418                 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
419         }
420
421         status = se_create_child_secdesc(ctx,
422                         &psd,
423                         &size,
424                         parent_desc,
425                         &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX],
426                         &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX],
427                         is_directory);
428         if (!NT_STATUS_IS_OK(status)) {
429                 return status;
430         }
431
432         if (DEBUGLEVEL >= 10) {
433                 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
434                         fsp_str_dbg(fsp) ));
435                 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
436         }
437
438         return SMB_VFS_FSET_NT_ACL(fsp,
439                                 (SECINFO_OWNER |
440                                  SECINFO_GROUP |
441                                  SECINFO_DACL),
442                                 psd);
443 }
444
445 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
446                                 const char *path,
447                                 uint32_t access_mask,
448                                 struct security_descriptor **pp_parent_desc)
449 {
450         char *parent_name = NULL;
451         struct security_descriptor *parent_desc = NULL;
452         uint32_t access_granted = 0;
453         NTSTATUS status;
454
455         if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
456                 return NT_STATUS_NO_MEMORY;
457         }
458
459         status = get_nt_acl_internal(handle,
460                                         NULL,
461                                         parent_name,
462                                         (SECINFO_OWNER |
463                                          SECINFO_GROUP |
464                                          SECINFO_DACL),
465                                         &parent_desc);
466
467         if (!NT_STATUS_IS_OK(status)) {
468                 DEBUG(10,("check_parent_acl_common: get_nt_acl_internal "
469                         "on directory %s for "
470                         "path %s returned %s\n",
471                         parent_name,
472                         path,
473                         nt_errstr(status) ));
474                 return status;
475         }
476         if (pp_parent_desc) {
477                 *pp_parent_desc = parent_desc;
478         }
479         status = smb1_file_se_access_check(handle->conn,
480                                         parent_desc,
481                                         get_current_nttok(handle->conn),
482                                         access_mask,
483                                         &access_granted);
484         if(!NT_STATUS_IS_OK(status)) {
485                 DEBUG(10,("check_parent_acl_common: access check "
486                         "on directory %s for "
487                         "path %s for mask 0x%x returned %s\n",
488                         parent_name,
489                         path,
490                         access_mask,
491                         nt_errstr(status) ));
492                 return status;
493         }
494         return NT_STATUS_OK;
495 }
496
497 static void free_sd_common(void **ptr)
498 {
499         TALLOC_FREE(*ptr);
500 }
501
502 /*********************************************************************
503  Check ACL on open. For new files inherit from parent directory.
504 *********************************************************************/
505
506 static int open_acl_common(vfs_handle_struct *handle,
507                         struct smb_filename *smb_fname,
508                         files_struct *fsp,
509                         int flags,
510                         mode_t mode)
511 {
512         uint32_t access_granted = 0;
513         struct security_descriptor *pdesc = NULL;
514         struct security_descriptor *parent_desc = NULL;
515         bool file_existed = true;
516         char *fname = NULL;
517         NTSTATUS status;
518
519         if (fsp->base_fsp) {
520                 /* Stream open. Base filename open already did the ACL check. */
521                 DEBUG(10,("open_acl_common: stream open on %s\n",
522                         fsp_str_dbg(fsp) ));
523                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
524         }
525
526         status = get_full_smb_filename(talloc_tos(), smb_fname,
527                                        &fname);
528         if (!NT_STATUS_IS_OK(status)) {
529                 goto err;
530         }
531
532         status = get_nt_acl_internal(handle,
533                                 NULL,
534                                 fname,
535                                 (SECINFO_OWNER |
536                                  SECINFO_GROUP |
537                                  SECINFO_DACL),
538                                 &pdesc);
539         if (NT_STATUS_IS_OK(status)) {
540                 /* See if we can access it. */
541                 status = smb1_file_se_access_check(handle->conn,
542                                         pdesc,
543                                         get_current_nttok(handle->conn),
544                                         fsp->access_mask,
545                                         &access_granted);
546                 if (!NT_STATUS_IS_OK(status)) {
547                         DEBUG(10,("open_acl_xattr: %s open "
548                                 "refused with error %s\n",
549                                 fsp_str_dbg(fsp),
550                                 nt_errstr(status) ));
551                         goto err;
552                 }
553         } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
554                 file_existed = false;
555                 /*
556                  * If O_CREAT is true then we're trying to create a file.
557                  * Check the parent directory ACL will allow this.
558                  */
559                 if (flags & O_CREAT) {
560                         struct security_descriptor *psd = NULL;
561
562                         status = check_parent_acl_common(handle, fname,
563                                         SEC_DIR_ADD_FILE, &parent_desc);
564                         if (!NT_STATUS_IS_OK(status)) {
565                                 goto err;
566                         }
567                         /* Cache the parent security descriptor for
568                          * later use. We do have an fsp here, but to
569                          * keep the code consistent with the directory
570                          * case which doesn't, use the handle. */
571
572                         /* Attach this to the conn, move from talloc_tos(). */
573                         psd = (struct security_descriptor *)talloc_move(handle->conn,
574                                 &parent_desc);
575
576                         if (!psd) {
577                                 status = NT_STATUS_NO_MEMORY;
578                                 goto err;
579                         }
580                         status = NT_STATUS_NO_MEMORY;
581                         SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
582                                 struct security_descriptor *, goto err);
583                         status = NT_STATUS_OK;
584                 }
585         }
586
587         DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
588                 "%s returned %s\n",
589                 fsp_str_dbg(fsp),
590                 nt_errstr(status) ));
591
592         fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
593         return fsp->fh->fd;
594
595   err:
596
597         errno = map_errno_from_nt_status(status);
598         return -1;
599 }
600
601 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
602 {
603         int ret;
604         NTSTATUS status;
605         SMB_STRUCT_STAT sbuf;
606
607         ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
608         if (ret == -1 && errno == ENOENT) {
609                 struct security_descriptor *parent_desc = NULL;
610                 struct security_descriptor *psd = NULL;
611
612                 /* We're creating a new directory. */
613                 status = check_parent_acl_common(handle, path,
614                                 SEC_DIR_ADD_SUBDIR, &parent_desc);
615                 if (!NT_STATUS_IS_OK(status)) {
616                         errno = map_errno_from_nt_status(status);
617                         return -1;
618                 }
619
620                 /* Cache the parent security descriptor for
621                  * later use. We don't have an fsp here so
622                  * use the handle. */
623
624                 /* Attach this to the conn, move from talloc_tos(). */
625                 psd = (struct security_descriptor *)talloc_move(handle->conn,
626                                 &parent_desc);
627
628                 if (!psd) {
629                         return -1;
630                 }
631                 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
632                         struct security_descriptor *, return -1);
633         }
634
635         return SMB_VFS_NEXT_MKDIR(handle, path, mode);
636 }
637
638 /*********************************************************************
639  Fetch a security descriptor given an fsp.
640 *********************************************************************/
641
642 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
643         uint32_t security_info, struct security_descriptor **ppdesc)
644 {
645         return get_nt_acl_internal(handle, fsp,
646                                 NULL, security_info, ppdesc);
647 }
648
649 /*********************************************************************
650  Fetch a security descriptor given a pathname.
651 *********************************************************************/
652
653 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
654         const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
655 {
656         return get_nt_acl_internal(handle, NULL,
657                                 name, security_info, ppdesc);
658 }
659
660 /*********************************************************************
661  Store a security descriptor given an fsp.
662 *********************************************************************/
663
664 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
665         uint32_t security_info_sent, const struct security_descriptor *psd)
666 {
667         NTSTATUS status;
668         DATA_BLOB blob;
669         struct security_descriptor *pdesc_next = NULL;
670         uint8_t hash[XATTR_SD_HASH_SIZE];
671
672         if (DEBUGLEVEL >= 10) {
673                 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
674                           fsp_str_dbg(fsp)));
675                 NDR_PRINT_DEBUG(security_descriptor,
676                         CONST_DISCARD(struct security_descriptor *,psd));
677         }
678
679         /* Ensure we have OWNER/GROUP/DACL set. */
680
681         if ((security_info_sent & (SECINFO_OWNER|
682                                 SECINFO_GROUP|
683                                 SECINFO_DACL)) !=
684                                 (SECINFO_OWNER|
685                                  SECINFO_GROUP|
686                                  SECINFO_DACL)) {
687                 /* No we don't - read from the existing SD. */
688                 struct security_descriptor *nc_psd = NULL;
689
690                 status = get_nt_acl_internal(handle, fsp,
691                                 NULL,
692                                 (SECINFO_OWNER|
693                                  SECINFO_GROUP|
694                                  SECINFO_DACL),
695                                 &nc_psd);
696
697                 if (!NT_STATUS_IS_OK(status)) {
698                         return status;
699                 }
700
701                 /* This is safe as nc_psd is discarded at fn exit. */
702                 if (security_info_sent & SECINFO_OWNER) {
703                         nc_psd->owner_sid = psd->owner_sid;
704                 }
705                 security_info_sent |= SECINFO_OWNER;
706
707                 if (security_info_sent & SECINFO_GROUP) {
708                         nc_psd->group_sid = psd->group_sid;
709                 }
710                 security_info_sent |= SECINFO_GROUP;
711
712                 if (security_info_sent & SECINFO_DACL) {
713                         nc_psd->dacl = dup_sec_acl(talloc_tos(), psd->dacl);
714                         if (nc_psd->dacl == NULL) {
715                                 return NT_STATUS_NO_MEMORY;
716                         }
717                 }
718                 security_info_sent |= SECINFO_DACL;
719                 psd = nc_psd;
720         }
721
722         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
723         if (!NT_STATUS_IS_OK(status)) {
724                 return status;
725         }
726
727         /* Get the full underlying sd, then hash. */
728         status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
729                                 fsp,
730                                 HASH_SECURITY_INFO,
731                                 &pdesc_next);
732
733         if (!NT_STATUS_IS_OK(status)) {
734                 return status;
735         }
736
737         status = hash_sd_sha256(pdesc_next, hash);
738         if (!NT_STATUS_IS_OK(status)) {
739                 return status;
740         }
741
742         if (DEBUGLEVEL >= 10) {
743                 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
744                           fsp_str_dbg(fsp)));
745                 NDR_PRINT_DEBUG(security_descriptor,
746                         CONST_DISCARD(struct security_descriptor *,psd));
747         }
748         create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
749         store_acl_blob_fsp(handle, fsp, &blob);
750
751         return NT_STATUS_OK;
752 }
753
754 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
755                         const char *fname, const char *mask, uint32 attr)
756 {
757         NTSTATUS status = check_parent_acl_common(handle, fname,
758                                         SEC_DIR_LIST, NULL);
759
760         if (!NT_STATUS_IS_OK(status)) {
761                 errno = map_errno_from_nt_status(status);
762                 return NULL;
763         }
764         return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
765 }
766
767 static int acl_common_remove_object(vfs_handle_struct *handle,
768                                         const char *path,
769                                         bool is_directory)
770 {
771         connection_struct *conn = handle->conn;
772         struct file_id id;
773         files_struct *fsp = NULL;
774         int ret = 0;
775         char *parent_dir = NULL;
776         const char *final_component = NULL;
777         struct smb_filename local_fname;
778         int saved_errno = 0;
779
780         if (!parent_dirname(talloc_tos(), path,
781                         &parent_dir, &final_component)) {
782                 saved_errno = ENOMEM;
783                 goto out;
784         }
785
786         DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
787                 is_directory ? "directory" : "file",
788                 parent_dir, final_component ));
789
790         /* cd into the parent dir to pin it. */
791         ret = SMB_VFS_CHDIR(conn, parent_dir);
792         if (ret == -1) {
793                 saved_errno = errno;
794                 goto out;
795         }
796
797         ZERO_STRUCT(local_fname);
798         local_fname.base_name = CONST_DISCARD(char *,final_component);
799
800         /* Must use lstat here. */
801         ret = SMB_VFS_LSTAT(conn, &local_fname);
802         if (ret == -1) {
803                 saved_errno = errno;
804                 goto out;
805         }
806
807         /* Ensure we have this file open with DELETE access. */
808         id = vfs_file_id_from_sbuf(conn, &local_fname.st);
809         for (fsp = file_find_di_first(id); fsp; file_find_di_next(fsp)) {
810                 if (fsp->access_mask & DELETE_ACCESS &&
811                                 fsp->delete_on_close) {
812                         /* We did open this for delete,
813                          * allow the delete as root.
814                          */
815                         break;
816                 }
817         }
818
819         if (!fsp) {
820                 DEBUG(10,("acl_common_remove_object: %s %s/%s "
821                         "not an open file\n",
822                         is_directory ? "directory" : "file",
823                         parent_dir, final_component ));
824                 saved_errno = EACCES;
825                 goto out;
826         }
827
828         become_root();
829         if (is_directory) {
830                 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
831         } else {
832                 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
833         }
834         unbecome_root();
835
836         if (ret == -1) {
837                 saved_errno = errno;
838         }
839
840   out:
841
842         TALLOC_FREE(parent_dir);
843
844         vfs_ChDir(conn, conn->connectpath);
845         if (saved_errno) {
846                 errno = saved_errno;
847         }
848         return ret;
849 }
850
851 static int rmdir_acl_common(struct vfs_handle_struct *handle,
852                                 const char *path)
853 {
854         int ret;
855
856         ret = SMB_VFS_NEXT_RMDIR(handle, path);
857         if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
858                 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
859                         path,
860                         strerror(errno) ));
861                 return ret;
862         }
863
864         return acl_common_remove_object(handle,
865                                         path,
866                                         true);
867 }
868
869 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
870                                 struct smb_request *req,
871                                 uint16_t root_dir_fid,
872                                 struct smb_filename *smb_fname,
873                                 uint32_t access_mask,
874                                 uint32_t share_access,
875                                 uint32_t create_disposition,
876                                 uint32_t create_options,
877                                 uint32_t file_attributes,
878                                 uint32_t oplock_request,
879                                 uint64_t allocation_size,
880                                 uint32_t private_flags,
881                                 struct security_descriptor *sd,
882                                 struct ea_list *ea_list,
883                                 files_struct **result,
884                                 int *pinfo)
885 {
886         NTSTATUS status, status1;
887         files_struct *fsp = NULL;
888         int info;
889         struct security_descriptor *parent_sd = NULL;
890
891         status = SMB_VFS_NEXT_CREATE_FILE(handle,
892                                         req,
893                                         root_dir_fid,
894                                         smb_fname,
895                                         access_mask,
896                                         share_access,
897                                         create_disposition,
898                                         create_options,
899                                         file_attributes,
900                                         oplock_request,
901                                         allocation_size,
902                                         private_flags,
903                                         sd,
904                                         ea_list,
905                                         result,
906                                         &info);
907
908         if (info != FILE_WAS_CREATED) {
909                 /* File/directory was opened, not created. */
910                 goto out;
911         }
912
913         fsp = *result;
914
915         if (!NT_STATUS_IS_OK(status) || fsp == NULL) {
916                 /* Only handle success. */
917                 goto out;
918         }
919
920         if (sd) {
921                 /* Security descriptor already set. */
922                 goto out;
923         }
924
925         if (fsp->base_fsp) {
926                 /* Stream open. */
927                 goto out;
928         }
929
930
931         /* We must have a cached parent sd in this case.
932          * attached to the handle. */
933
934         SMB_VFS_HANDLE_GET_DATA(handle, parent_sd,
935                 struct security_descriptor,
936                 goto err);
937
938         if (!parent_sd) {
939                 goto err;
940         }
941
942         /* New directory - inherit from parent. */
943         status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
944
945         if (!NT_STATUS_IS_OK(status1)) {
946                 DEBUG(1,("create_file_acl_common: error setting "
947                         "sd for %s (%s)\n",
948                         fsp_str_dbg(fsp),
949                         nt_errstr(status1) ));
950         }
951
952   out:
953
954         /* Ensure we never leave attached data around. */
955         SMB_VFS_HANDLE_FREE_DATA(handle);
956
957         if (NT_STATUS_IS_OK(status) && pinfo) {
958                 *pinfo = info;
959         }
960         return status;
961
962   err:
963
964         smb_panic("create_file_acl_common: logic error.\n");
965         /* NOTREACHED */
966         return status;
967 }
968
969 static int unlink_acl_common(struct vfs_handle_struct *handle,
970                         const struct smb_filename *smb_fname)
971 {
972         int ret;
973
974         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
975         if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
976                 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
977                         smb_fname->base_name,
978                         strerror(errno) ));
979                 return ret;
980         }
981         /* Don't do anything fancy for streams. */
982         if (smb_fname->stream_name) {
983                 return ret;
984         }
985
986         return acl_common_remove_object(handle,
987                                         smb_fname->base_name,
988                                         false);
989 }