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