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