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