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