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