s3: Finish plumbing the fsp->fsp_name smb_fname conversion through the modules.
[kai/samba-autobuild/.git] / source3 / modules / vfs_acl_xattr.c
1 /*
2  * Store Windows ACLs in xattrs.
3  *
4  * Copyright (C) Volker Lendecke, 2008
5  * Copyright (C) Jeremy Allison, 2008
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 /* NOTE: This is an experimental module, not yet finished. JRA. */
22
23 #include "includes.h"
24 #include "librpc/gen_ndr/xattr.h"
25 #include "librpc/gen_ndr/ndr_xattr.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_VFS
29
30 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
31                         DATA_BLOB *pblob,
32                         uint8_t hash[16]);
33
34 #define HASH_SECURITY_INFO (OWNER_SECURITY_INFORMATION | \
35                                 GROUP_SECURITY_INFORMATION | \
36                                 DACL_SECURITY_INFORMATION | \
37                                 SACL_SECURITY_INFORMATION)
38
39 /*******************************************************************
40  Hash a security descriptor.
41 *******************************************************************/
42
43 static NTSTATUS hash_sd(struct security_descriptor *psd,
44                         uint8_t hash[16])
45 {
46         DATA_BLOB blob;
47         struct MD5Context tctx;
48         NTSTATUS status;
49
50         memset(hash, '\0', 16);
51         status = create_acl_blob(psd, &blob, hash);
52         if (!NT_STATUS_IS_OK(status)) {
53                 return status;
54         }
55         MD5Init(&tctx);
56         MD5Update(&tctx, blob.data, blob.length);
57         MD5Final(hash, &tctx);
58         return NT_STATUS_OK;
59 }
60
61 /*******************************************************************
62  Parse out a struct security_descriptor from a DATA_BLOB.
63 *******************************************************************/
64
65 static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
66                                 uint32 security_info,
67                                 struct security_descriptor **ppdesc,
68                                 uint8_t hash[16])
69 {
70         TALLOC_CTX *ctx = talloc_tos();
71         struct xattr_NTACL xacl;
72         enum ndr_err_code ndr_err;
73         size_t sd_size;
74
75         ndr_err = ndr_pull_struct_blob(pblob, ctx, NULL, &xacl,
76                         (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
77
78         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
79                 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
80                         ndr_errstr(ndr_err)));
81                 return ndr_map_error2ntstatus(ndr_err);;
82         }
83
84         if (xacl.version != 2) {
85                 return NT_STATUS_REVISION_MISMATCH;
86         }
87
88         *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION, xacl.info.sd_hs->sd->type | SEC_DESC_SELF_RELATIVE,
89                         (security_info & OWNER_SECURITY_INFORMATION)
90                         ? xacl.info.sd_hs->sd->owner_sid : NULL,
91                         (security_info & GROUP_SECURITY_INFORMATION)
92                         ? xacl.info.sd_hs->sd->group_sid : NULL,
93                         (security_info & SACL_SECURITY_INFORMATION)
94                         ? xacl.info.sd_hs->sd->sacl : NULL,
95                         (security_info & DACL_SECURITY_INFORMATION)
96                         ? xacl.info.sd_hs->sd->dacl : NULL,
97                         &sd_size);
98
99         memcpy(hash, xacl.info.sd_hs->hash, 16);
100         TALLOC_FREE(xacl.info.sd);
101
102         return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
103 }
104
105 /*******************************************************************
106  Pull a security descriptor into a DATA_BLOB from a xattr.
107 *******************************************************************/
108
109 static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
110                         vfs_handle_struct *handle,
111                         files_struct *fsp,
112                         const char *name,
113                         DATA_BLOB *pblob)
114 {
115         size_t size = 1024;
116         uint8_t *val = NULL;
117         uint8_t *tmp;
118         ssize_t sizeret;
119         int saved_errno = 0;
120
121         ZERO_STRUCTP(pblob);
122
123   again:
124
125         tmp = TALLOC_REALLOC_ARRAY(ctx, val, uint8_t, size);
126         if (tmp == NULL) {
127                 TALLOC_FREE(val);
128                 return NT_STATUS_NO_MEMORY;
129         }
130         val = tmp;
131
132         become_root();
133         if (fsp && fsp->fh->fd != -1) {
134                 sizeret = SMB_VFS_FGETXATTR(fsp, XATTR_NTACL_NAME, val, size);
135         } else {
136                 sizeret = SMB_VFS_GETXATTR(handle->conn, name,
137                                         XATTR_NTACL_NAME, val, size);
138         }
139         if (sizeret == -1) {
140                 saved_errno = errno;
141         }
142         unbecome_root();
143
144         /* Max ACL size is 65536 bytes. */
145         if (sizeret == -1) {
146                 errno = saved_errno;
147                 if ((errno == ERANGE) && (size != 65536)) {
148                         /* Too small, try again. */
149                         size = 65536;
150                         goto again;
151                 }
152
153                 /* Real error - exit here. */
154                 TALLOC_FREE(val);
155                 return map_nt_error_from_unix(errno);
156         }
157
158         pblob->data = val;
159         pblob->length = sizeret;
160         return NT_STATUS_OK;
161 }
162
163 /*******************************************************************
164  Create a DATA_BLOB from a security descriptor.
165 *******************************************************************/
166
167 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
168                         DATA_BLOB *pblob,
169                         uint8_t hash[16])
170 {
171         struct xattr_NTACL xacl;
172         struct security_descriptor_hash sd_hs;
173         enum ndr_err_code ndr_err;
174         TALLOC_CTX *ctx = talloc_tos();
175
176         ZERO_STRUCT(xacl);
177         ZERO_STRUCT(sd_hs);
178
179         xacl.version = 2;
180         xacl.info.sd_hs = &sd_hs;
181         xacl.info.sd_hs->sd = CONST_DISCARD(struct security_descriptor *, psd);
182         memcpy(&xacl.info.sd_hs->hash[0], hash, 16);
183
184         ndr_err = ndr_push_struct_blob(
185                         pblob, ctx, NULL, &xacl,
186                         (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
187
188         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
189                 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
190                         ndr_errstr(ndr_err)));
191                 return ndr_map_error2ntstatus(ndr_err);;
192         }
193
194         return NT_STATUS_OK;
195 }
196
197 /*******************************************************************
198  Store a DATA_BLOB into an xattr given an fsp pointer.
199 *******************************************************************/
200
201 static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
202                                 files_struct *fsp,
203                                 DATA_BLOB *pblob)
204 {
205         int ret;
206         int saved_errno = 0;
207
208         DEBUG(10,("store_acl_blob_fsp: storing blob length %u on file %s\n",
209                   (unsigned int)pblob->length, fsp_str_dbg(fsp)));
210
211         become_root();
212         if (fsp->fh->fd != -1) {
213                 ret = SMB_VFS_FSETXATTR(fsp, XATTR_NTACL_NAME,
214                         pblob->data, pblob->length, 0);
215         } else {
216                 ret = SMB_VFS_SETXATTR(fsp->conn, fsp->fsp_name->base_name,
217                                 XATTR_NTACL_NAME,
218                                 pblob->data, pblob->length, 0);
219         }
220         if (ret) {
221                 saved_errno = errno;
222         }
223         unbecome_root();
224         if (ret) {
225                 errno = saved_errno;
226                 DEBUG(5, ("store_acl_blob_fsp: setting attr failed for file %s"
227                         "with error %s\n",
228                         fsp_str_dbg(fsp),
229                         strerror(errno) ));
230                 return map_nt_error_from_unix(errno);
231         }
232         return NT_STATUS_OK;
233 }
234
235 /*******************************************************************
236  Store a DATA_BLOB into an xattr given a pathname.
237 *******************************************************************/
238
239 static NTSTATUS store_acl_blob_pathname(vfs_handle_struct *handle,
240                                         const char *fname,
241                                         DATA_BLOB *pblob)
242 {
243         connection_struct *conn = handle->conn;
244         int ret;
245         int saved_errno = 0;
246
247         DEBUG(10,("store_acl_blob_pathname: storing blob "
248                         "length %u on file %s\n",
249                         (unsigned int)pblob->length, fname));
250
251         become_root();
252         ret = SMB_VFS_SETXATTR(conn, fname,
253                                 XATTR_NTACL_NAME,
254                                 pblob->data, pblob->length, 0);
255         if (ret) {
256                 saved_errno = errno;
257         }
258         unbecome_root();
259         if (ret) {
260                 errno = saved_errno;
261                 DEBUG(5, ("store_acl_blob_pathname: setting attr failed "
262                         "for file %s with error %s\n",
263                         fname,
264                         strerror(errno) ));
265                 return map_nt_error_from_unix(errno);
266         }
267         return NT_STATUS_OK;
268 }
269
270 /*******************************************************************
271  Store a DATA_BLOB into an xattr given a pathname.
272 *******************************************************************/
273
274 static NTSTATUS get_nt_acl_xattr_internal(vfs_handle_struct *handle,
275                                         files_struct *fsp,
276                                         const char *name,
277                                         uint32 security_info,
278                                         struct security_descriptor **ppdesc)
279 {
280         DATA_BLOB blob;
281         NTSTATUS status;
282         uint8_t hash[16];
283         uint8_t hash_tmp[16];
284         struct security_descriptor *pdesc_next = NULL;
285
286         if (fsp && name == NULL) {
287                 name = fsp->fsp_name->base_name;
288         }
289
290         DEBUG(10, ("get_nt_acl_xattr_internal: name=%s\n", name));
291
292         status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
293         if (!NT_STATUS_IS_OK(status)) {
294                 DEBUG(10, ("get_acl_blob returned %s\n", nt_errstr(status)));
295                 return status;
296         }
297
298         status = parse_acl_blob(&blob, security_info, ppdesc, &hash[0]);
299         if (!NT_STATUS_IS_OK(status)) {
300                 DEBUG(10, ("parse_acl_blob returned %s\n",
301                                 nt_errstr(status)));
302                 return status;
303         }
304
305         /* If there was no stored hash, don't check. */
306         memset(&hash_tmp[0], '\0', 16);
307         if (memcmp(&hash[0], &hash_tmp[0], 16) == 0) {
308                 /* No hash, goto return blob sd. */
309                 goto out;
310         }
311
312         /* Get the full underlying sd, then hash. */
313         if (fsp) {
314                 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
315                                 fsp,
316                                 HASH_SECURITY_INFO,
317                                 &pdesc_next);
318         } else {
319                 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
320                                 name,
321                                 HASH_SECURITY_INFO,
322                                 &pdesc_next);
323         }
324
325         if (!NT_STATUS_IS_OK(status)) {
326                 goto out;
327         }
328
329         status = hash_sd(pdesc_next, hash_tmp);
330         if (!NT_STATUS_IS_OK(status)) {
331                 goto out;
332         }
333
334         if (memcmp(&hash[0], &hash_tmp[0], 16) == 0) {
335                 TALLOC_FREE(pdesc_next);
336                 /* Hash matches, return blob sd. */
337                 goto out;
338         }
339
340         /* Hash doesn't match, return underlying sd. */
341
342         if (!(security_info & OWNER_SECURITY_INFORMATION)) {
343                 pdesc_next->owner_sid = NULL;
344         }
345         if (!(security_info & GROUP_SECURITY_INFORMATION)) {
346                 pdesc_next->group_sid = NULL;
347         }
348         if (!(security_info & DACL_SECURITY_INFORMATION)) {
349                 pdesc_next->dacl = NULL;
350         }
351         if (!(security_info & SACL_SECURITY_INFORMATION)) {
352                 pdesc_next->sacl = NULL;
353         }
354
355         TALLOC_FREE(*ppdesc);
356         *ppdesc = pdesc_next;
357
358   out:
359
360         TALLOC_FREE(blob.data);
361         return status;
362 }
363
364 /*********************************************************************
365  Create a default security descriptor for a file in case no inheritance
366  exists. All permissions to the owner and SYSTEM.
367 *********************************************************************/
368
369 static struct security_descriptor *default_file_sd(TALLOC_CTX *mem_ctx,
370                                                 SMB_STRUCT_STAT *psbuf)
371 {
372         struct dom_sid owner_sid, group_sid;
373         size_t sd_size;
374         struct security_ace *pace = NULL;
375         struct security_acl *pacl = NULL;
376
377         uid_to_sid(&owner_sid, psbuf->st_ex_uid);
378         gid_to_sid(&group_sid, psbuf->st_ex_gid);
379
380         pace = TALLOC_ARRAY(mem_ctx, struct security_ace, 2);
381         if (!pace) {
382                 return NULL;
383         }
384
385         init_sec_ace(&pace[0], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
386                         SEC_RIGHTS_FILE_ALL, 0);
387         init_sec_ace(&pace[1], &global_sid_System, SEC_ACE_TYPE_ACCESS_ALLOWED,
388                         SEC_RIGHTS_FILE_ALL, 0);
389
390         pacl = make_sec_acl(mem_ctx,
391                                 NT4_ACL_REVISION,
392                                 2,
393                                 pace);
394         if (!pacl) {
395                 return NULL;
396         }
397         return make_sec_desc(mem_ctx,
398                         SECURITY_DESCRIPTOR_REVISION_1,
399                         SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
400                         &owner_sid,
401                         &group_sid,
402                         NULL,
403                         pacl,
404                         &sd_size);
405 }
406
407 /*********************************************************************
408 *********************************************************************/
409
410 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
411                                         struct smb_filename *smb_fname,
412                                         files_struct *fsp,
413                                         bool container)
414 {
415         TALLOC_CTX *ctx = talloc_tos();
416         NTSTATUS status;
417         struct security_descriptor *parent_desc = NULL;
418         struct security_descriptor *psd = NULL;
419         struct security_descriptor *pdesc_next = NULL;
420         DATA_BLOB blob;
421         size_t size;
422         char *parent_name;
423         uint8_t hash[16];
424
425         if (!parent_dirname(ctx, smb_fname->base_name, &parent_name, NULL)) {
426                 return NT_STATUS_NO_MEMORY;
427         }
428
429         DEBUG(10,("inherit_new_acl: check directory %s\n",
430                         parent_name));
431
432         status = get_nt_acl_xattr_internal(handle,
433                                         NULL,
434                                         parent_name,
435                                         (OWNER_SECURITY_INFORMATION |
436                                          GROUP_SECURITY_INFORMATION |
437                                          DACL_SECURITY_INFORMATION),
438                                         &parent_desc);
439         if (NT_STATUS_IS_OK(status)) {
440                 /* Create an inherited descriptor from the parent. */
441
442                 if (DEBUGLEVEL >= 10) {
443                         DEBUG(10,("inherit_new_acl: parent acl is:\n"));
444                         NDR_PRINT_DEBUG(security_descriptor, parent_desc);
445                 }
446
447                 status = se_create_child_secdesc(ctx,
448                                 &psd,
449                                 &size,
450                                 parent_desc,
451                                 &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX],
452                                 &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX],
453                                 container);
454                 if (!NT_STATUS_IS_OK(status)) {
455                         return status;
456                 }
457
458                 if (DEBUGLEVEL >= 10) {
459                         DEBUG(10,("inherit_new_acl: child acl is:\n"));
460                         NDR_PRINT_DEBUG(security_descriptor, psd);
461                 }
462
463         } else {
464                 DEBUG(10,("inherit_new_acl: directory %s failed "
465                         "to get acl %s\n",
466                         parent_name,
467                         nt_errstr(status) ));
468         }
469
470         if (!psd || psd->dacl == NULL) {
471                 int ret;
472
473                 TALLOC_FREE(psd);
474                 if (fsp && !fsp->is_directory && fsp->fh->fd != -1) {
475                         ret = SMB_VFS_FSTAT(fsp, &smb_fname->st);
476                 } else {
477                         if (fsp && fsp->posix_open) {
478                                 ret = SMB_VFS_LSTAT(handle->conn, smb_fname);
479                         } else {
480                                 ret = SMB_VFS_STAT(handle->conn, smb_fname);
481                         }
482                 }
483                 if (ret == -1) {
484                         return map_nt_error_from_unix(errno);
485                 }
486                 psd = default_file_sd(ctx, &smb_fname->st);
487                 if (!psd) {
488                         return NT_STATUS_NO_MEMORY;
489                 }
490
491                 if (DEBUGLEVEL >= 10) {
492                         DEBUG(10,("inherit_new_acl: default acl is:\n"));
493                         NDR_PRINT_DEBUG(security_descriptor, psd);
494                 }
495         }
496
497         /* Object exists. Read the current SD to get the hash. */
498         if (fsp) {
499                 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
500                                 fsp,
501                                 HASH_SECURITY_INFO,
502                                 &pdesc_next);
503         } else {
504                 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
505                                 smb_fname->base_name,
506                                 HASH_SECURITY_INFO,
507                                 &pdesc_next);
508         }
509
510         if (!NT_STATUS_IS_OK(status)) {
511                 return status;
512         }
513
514         status = hash_sd(pdesc_next, hash);
515         if (!NT_STATUS_IS_OK(status)) {
516                 return status;
517         }
518         status = create_acl_blob(psd, &blob, hash);
519         if (!NT_STATUS_IS_OK(status)) {
520                 return status;
521         }
522         if (fsp) {
523                 return store_acl_blob_fsp(handle, fsp, &blob);
524         } else {
525                 return store_acl_blob_pathname(handle, smb_fname->base_name,
526                                                &blob);
527         }
528 }
529
530 /*********************************************************************
531  Check ACL on open. For new files inherit from parent directory.
532 *********************************************************************/
533
534 static int open_acl_xattr(vfs_handle_struct *handle,
535                                         struct smb_filename *smb_fname,
536                                         files_struct *fsp,
537                                         int flags,
538                                         mode_t mode)
539 {
540         uint32_t access_granted = 0;
541         struct security_descriptor *pdesc = NULL;
542         bool file_existed = true;
543         char *fname = NULL;
544         NTSTATUS status;
545
546         if (fsp->base_fsp) {
547                 /* Stream open. Base filename open already did the ACL check. */
548                 DEBUG(10,("open_acl_xattr: stream open on %s\n",
549                         smb_fname_str_dbg(smb_fname) ));
550                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
551         }
552
553         status = get_full_smb_filename(talloc_tos(), smb_fname,
554                                        &fname);
555         if (!NT_STATUS_IS_OK(status)) {
556                 errno = map_errno_from_nt_status(status);
557                 return -1;
558         }
559
560         status = get_nt_acl_xattr_internal(handle,
561                                         NULL,
562                                         fname,
563                                         (OWNER_SECURITY_INFORMATION |
564                                          GROUP_SECURITY_INFORMATION |
565                                          DACL_SECURITY_INFORMATION),
566                                         &pdesc);
567         if (NT_STATUS_IS_OK(status)) {
568                 /* See if we can access it. */
569                 status = smb1_file_se_access_check(pdesc,
570                                         handle->conn->server_info->ptok,
571                                         fsp->access_mask,
572                                         &access_granted);
573                 if (!NT_STATUS_IS_OK(status)) {
574                         DEBUG(10,("open_acl_xattr: file %s open "
575                                 "refused with error %s\n",
576                                 smb_fname_str_dbg(smb_fname),
577                                 nt_errstr(status) ));
578                         errno = map_errno_from_nt_status(status);
579                         return -1;
580                 }
581         } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
582                 file_existed = false;
583         }
584
585         DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
586                 "file %s returned %s\n",
587                 smb_fname_str_dbg(smb_fname),
588                 nt_errstr(status) ));
589
590         fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
591
592         if (!file_existed && fsp->fh->fd != -1) {
593                 /* File was created. Inherit from parent directory. */
594                 status = fsp_set_smb_fname(fsp, smb_fname);
595                 if (!NT_STATUS_IS_OK(status)) {
596                         errno = map_errno_from_nt_status(status);
597                         return -1;
598                 }
599                 inherit_new_acl(handle, smb_fname, fsp, false);
600         }
601
602         return fsp->fh->fd;
603 }
604
605 static int mkdir_acl_xattr(vfs_handle_struct *handle, const char *path, mode_t mode)
606 {
607         struct smb_filename *smb_fname = NULL;
608         int ret = SMB_VFS_NEXT_MKDIR(handle, path, mode);
609         NTSTATUS status;
610
611         if (ret == -1) {
612                 return ret;
613         }
614
615         status = create_synthetic_smb_fname(talloc_tos(), path, NULL, NULL,
616                                             &smb_fname);
617         if (!NT_STATUS_IS_OK(status)) {
618                 errno = map_errno_from_nt_status(status);
619                 return -1;
620         }
621
622         /* New directory - inherit from parent. */
623         inherit_new_acl(handle, smb_fname, NULL, true);
624         TALLOC_FREE(smb_fname);
625         return ret;
626 }
627
628 /*********************************************************************
629  Fetch a security descriptor given an fsp.
630 *********************************************************************/
631
632 static NTSTATUS fget_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp,
633         uint32 security_info, struct security_descriptor **ppdesc)
634 {
635         return get_nt_acl_xattr_internal(handle, fsp,
636                                 NULL, security_info, ppdesc);
637 }
638
639 /*********************************************************************
640  Fetch a security descriptor given a pathname.
641 *********************************************************************/
642
643 static NTSTATUS get_nt_acl_xattr(vfs_handle_struct *handle,
644         const char *name, uint32 security_info, struct security_descriptor **ppdesc)
645 {
646         return get_nt_acl_xattr_internal(handle, NULL,
647                                 name, security_info, ppdesc);
648 }
649
650 /*********************************************************************
651  Store a security descriptor given an fsp.
652 *********************************************************************/
653
654 static NTSTATUS fset_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp,
655         uint32 security_info_sent, const struct security_descriptor *psd)
656 {
657         NTSTATUS status;
658         DATA_BLOB blob;
659         struct security_descriptor *pdesc_next = NULL;
660         uint8_t hash[16];
661
662         if (DEBUGLEVEL >= 10) {
663                 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
664                           fsp_str_dbg(fsp)));
665                 NDR_PRINT_DEBUG(security_descriptor,
666                         CONST_DISCARD(struct security_descriptor *,psd));
667         }
668
669         /* Ensure owner and group are set. */
670         if (!psd->owner_sid || !psd->group_sid) {
671                 int ret;
672                 DOM_SID owner_sid, group_sid;
673                 struct security_descriptor *nc_psd = dup_sec_desc(talloc_tos(), psd);
674
675                 if (!nc_psd) {
676                         return NT_STATUS_OK;
677                 }
678                 if (fsp->is_directory || fsp->fh->fd == -1) {
679                         if (fsp->posix_open) {
680                                 ret = SMB_VFS_LSTAT(fsp->conn, fsp->fsp_name);
681                         } else {
682                                 ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name);
683                         }
684                 } else {
685                         ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
686                 }
687                 if (ret == -1) {
688                         /* Lower level acl set succeeded,
689                          * so still return OK. */
690                         return NT_STATUS_OK;
691                 }
692                 create_file_sids(&fsp->fsp_name->st, &owner_sid, &group_sid);
693                 /* This is safe as nc_psd is discarded at fn exit. */
694                 nc_psd->owner_sid = &owner_sid;
695                 nc_psd->group_sid = &group_sid;
696                 security_info_sent |= (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION);
697                 psd = nc_psd;
698         }
699
700         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
701         if (!NT_STATUS_IS_OK(status)) {
702                 return status;
703         }
704
705         /* Get the full underlying sd, then hash. */
706         status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
707                                 fsp,
708                                 HASH_SECURITY_INFO,
709                                 &pdesc_next);
710
711         if (!NT_STATUS_IS_OK(status)) {
712                 return status;
713         }
714
715         status = hash_sd(pdesc_next, hash);
716         if (!NT_STATUS_IS_OK(status)) {
717                 return status;
718         }
719
720 #if 0
721         if ((security_info_sent & DACL_SECURITY_INFORMATION) &&
722                         psd->dacl != NULL &&
723                         (psd->type & (SE_DESC_DACL_AUTO_INHERITED|
724                                 SE_DESC_DACL_AUTO_INHERIT_REQ))==
725                                 (SE_DESC_DACL_AUTO_INHERITED|
726                                 SE_DESC_DACL_AUTO_INHERIT_REQ) ) {
727                 struct security_descriptor *new_psd = NULL;
728                 status = append_parent_acl(fsp, psd, &new_psd);
729                 if (!NT_STATUS_IS_OK(status)) {
730                         /* Lower level acl set succeeded,
731                          * so still return OK. */
732                         return NT_STATUS_OK;
733                 }
734                 psd = new_psd;
735         }
736 #endif
737
738         if (DEBUGLEVEL >= 10) {
739                 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
740                           fsp_str_dbg(fsp)));
741                 NDR_PRINT_DEBUG(security_descriptor,
742                         CONST_DISCARD(struct security_descriptor *,psd));
743         }
744         create_acl_blob(psd, &blob, hash);
745         store_acl_blob_fsp(handle, fsp, &blob);
746
747         return NT_STATUS_OK;
748 }
749
750 /*********************************************************************
751  Remove a Windows ACL - we're setting the underlying POSIX ACL.
752 *********************************************************************/
753
754 static int sys_acl_set_file_xattr(vfs_handle_struct *handle,
755                               const char *name,
756                               SMB_ACL_TYPE_T type,
757                               SMB_ACL_T theacl)
758 {
759         int ret = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle,
760                                                 name,
761                                                 type,
762                                                 theacl);
763         if (ret == -1) {
764                 return -1;
765         }
766
767         become_root();
768         SMB_VFS_REMOVEXATTR(handle->conn, name, XATTR_NTACL_NAME);
769         unbecome_root();
770
771         return ret;
772 }
773
774 /*********************************************************************
775  Remove a Windows ACL - we're setting the underlying POSIX ACL.
776 *********************************************************************/
777
778 static int sys_acl_set_fd_xattr(vfs_handle_struct *handle,
779                             files_struct *fsp,
780                             SMB_ACL_T theacl)
781 {
782         int ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle,
783                                                 fsp,
784                                                 theacl);
785         if (ret == -1) {
786                 return -1;
787         }
788
789         become_root();
790         SMB_VFS_FREMOVEXATTR(fsp, XATTR_NTACL_NAME);
791         unbecome_root();
792
793         return ret;
794 }
795
796 /* VFS operations structure */
797
798 static vfs_op_tuple skel_op_tuples[] =
799 {
800         {SMB_VFS_OP(mkdir_acl_xattr), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_TRANSPARENT},
801         {SMB_VFS_OP(open_acl_xattr),  SMB_VFS_OP_OPEN,  SMB_VFS_LAYER_TRANSPARENT},
802
803         /* NT File ACL operations */
804
805         {SMB_VFS_OP(fget_nt_acl_xattr),SMB_VFS_OP_FGET_NT_ACL,SMB_VFS_LAYER_TRANSPARENT},
806         {SMB_VFS_OP(get_nt_acl_xattr), SMB_VFS_OP_GET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT},
807         {SMB_VFS_OP(fset_nt_acl_xattr),SMB_VFS_OP_FSET_NT_ACL,SMB_VFS_LAYER_TRANSPARENT},
808
809         /* POSIX ACL operations. */
810         {SMB_VFS_OP(sys_acl_set_file_xattr), SMB_VFS_OP_SYS_ACL_SET_FILE, SMB_VFS_LAYER_TRANSPARENT},
811         {SMB_VFS_OP(sys_acl_set_fd_xattr), SMB_VFS_OP_SYS_ACL_SET_FD, SMB_VFS_LAYER_TRANSPARENT},
812
813         {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
814 };
815
816 NTSTATUS vfs_acl_xattr_init(void)
817 {
818         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "acl_xattr", skel_op_tuples);
819 }