Add hash values to the xattr ACLS to determine when
[samba.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->fsp_name));
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,
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->fsp_name,
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;
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                                         const char *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, fname, &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                 SMB_STRUCT_STAT sbuf;
472                 int ret;
473
474                 TALLOC_FREE(psd);
475                 if (fsp && !fsp->is_directory && fsp->fh->fd != -1) {
476                         ret = SMB_VFS_FSTAT(fsp, &sbuf);
477                 } else {
478                         if (fsp && fsp->posix_open) {
479                                 ret = vfs_lstat_smb_fname(handle->conn,fname, &sbuf);
480                         } else {
481                                 ret = vfs_stat_smb_fname(handle->conn,fname, &sbuf);
482                         }
483                 }
484                 if (ret == -1) {
485                         return map_nt_error_from_unix(errno);
486                 }
487                 psd = default_file_sd(ctx, &sbuf);
488                 if (!psd) {
489                         return NT_STATUS_NO_MEMORY;
490                 }
491
492                 if (DEBUGLEVEL >= 10) {
493                         DEBUG(10,("inherit_new_acl: default acl is:\n"));
494                         NDR_PRINT_DEBUG(security_descriptor, psd);
495                 }
496         }
497
498         /* Object exists. Read the current SD to get the hash. */
499         if (fsp) {
500                 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
501                                 fsp,
502                                 HASH_SECURITY_INFO,
503                                 &pdesc_next);
504         } else {
505                 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
506                                 fname,
507                                 HASH_SECURITY_INFO,
508                                 &pdesc_next);
509         }
510
511         if (!NT_STATUS_IS_OK(status)) {
512                 return status;
513         }
514
515         status = hash_sd(pdesc_next, hash);
516         if (!NT_STATUS_IS_OK(status)) {
517                 return status;
518         }
519         status = create_acl_blob(psd, &blob, hash);
520         if (!NT_STATUS_IS_OK(status)) {
521                 return status;
522         }
523         if (fsp) {
524                 return store_acl_blob_fsp(handle, fsp, &blob);
525         } else {
526                 return store_acl_blob_pathname(handle, fname, &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                 string_set(&fsp->fsp_name, fname);
595                 inherit_new_acl(handle, fname, fsp, false);
596         }
597
598         return fsp->fh->fd;
599 }
600
601 static int mkdir_acl_xattr(vfs_handle_struct *handle, const char *path, mode_t mode)
602 {
603         int ret = SMB_VFS_NEXT_MKDIR(handle, path, mode);
604
605         if (ret == -1) {
606                 return ret;
607         }
608         /* New directory - inherit from parent. */
609         inherit_new_acl(handle, path, NULL, true);
610         return ret;
611 }
612
613 /*********************************************************************
614  Fetch a security descriptor given an fsp.
615 *********************************************************************/
616
617 static NTSTATUS fget_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp,
618         uint32 security_info, struct security_descriptor **ppdesc)
619 {
620         return get_nt_acl_xattr_internal(handle, fsp,
621                                 NULL, security_info, ppdesc);
622 }
623
624 /*********************************************************************
625  Fetch a security descriptor given a pathname.
626 *********************************************************************/
627
628 static NTSTATUS get_nt_acl_xattr(vfs_handle_struct *handle,
629         const char *name, uint32 security_info, struct security_descriptor **ppdesc)
630 {
631         return get_nt_acl_xattr_internal(handle, NULL,
632                                 name, security_info, ppdesc);
633 }
634
635 /*********************************************************************
636  Store a security descriptor given an fsp.
637 *********************************************************************/
638
639 static NTSTATUS fset_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp,
640         uint32 security_info_sent, const struct security_descriptor *psd)
641 {
642         NTSTATUS status;
643         DATA_BLOB blob;
644         struct security_descriptor *pdesc_next = NULL;
645         uint8_t hash[16];
646
647         if (DEBUGLEVEL >= 10) {
648                 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
649                         fsp->fsp_name));
650                 NDR_PRINT_DEBUG(security_descriptor,
651                         CONST_DISCARD(struct security_descriptor *,psd));
652         }
653
654         /* Ensure owner and group are set. */
655         if (!psd->owner_sid || !psd->group_sid) {
656                 int ret;
657                 SMB_STRUCT_STAT sbuf;
658                 DOM_SID owner_sid, group_sid;
659                 struct security_descriptor *nc_psd = dup_sec_desc(talloc_tos(), psd);
660
661                 if (!nc_psd) {
662                         return NT_STATUS_OK;
663                 }
664                 if (fsp->is_directory || fsp->fh->fd == -1) {
665                         if (fsp->posix_open) {
666                                 ret = vfs_lstat_smb_fname(fsp->conn,fsp->fsp_name, &sbuf);
667                         } else {
668                                 ret = vfs_stat_smb_fname(fsp->conn,fsp->fsp_name, &sbuf);
669                         }
670                 } else {
671                         ret = SMB_VFS_FSTAT(fsp, &sbuf);
672                 }
673                 if (ret == -1) {
674                         /* Lower level acl set succeeded,
675                          * so still return OK. */
676                         return NT_STATUS_OK;
677                 }
678                 create_file_sids(&sbuf, &owner_sid, &group_sid);
679                 /* This is safe as nc_psd is discarded at fn exit. */
680                 nc_psd->owner_sid = &owner_sid;
681                 nc_psd->group_sid = &group_sid;
682                 security_info_sent |= (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION);
683                 psd = nc_psd;
684         }
685
686         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
687         if (!NT_STATUS_IS_OK(status)) {
688                 return status;
689         }
690
691         /* Get the full underlying sd, then hash. */
692         status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
693                                 fsp,
694                                 HASH_SECURITY_INFO,
695                                 &pdesc_next);
696
697         if (!NT_STATUS_IS_OK(status)) {
698                 return status;
699         }
700
701         status = hash_sd(pdesc_next, hash);
702         if (!NT_STATUS_IS_OK(status)) {
703                 return status;
704         }
705
706 #if 0
707         if ((security_info_sent & DACL_SECURITY_INFORMATION) &&
708                         psd->dacl != NULL &&
709                         (psd->type & (SE_DESC_DACL_AUTO_INHERITED|
710                                 SE_DESC_DACL_AUTO_INHERIT_REQ))==
711                                 (SE_DESC_DACL_AUTO_INHERITED|
712                                 SE_DESC_DACL_AUTO_INHERIT_REQ) ) {
713                 struct security_descriptor *new_psd = NULL;
714                 status = append_parent_acl(fsp, psd, &new_psd);
715                 if (!NT_STATUS_IS_OK(status)) {
716                         /* Lower level acl set succeeded,
717                          * so still return OK. */
718                         return NT_STATUS_OK;
719                 }
720                 psd = new_psd;
721         }
722 #endif
723
724         if (DEBUGLEVEL >= 10) {
725                 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
726                         fsp->fsp_name));
727                 NDR_PRINT_DEBUG(security_descriptor,
728                         CONST_DISCARD(struct security_descriptor *,psd));
729         }
730         create_acl_blob(psd, &blob, hash);
731         store_acl_blob_fsp(handle, fsp, &blob);
732
733         return NT_STATUS_OK;
734 }
735
736 /*********************************************************************
737  Remove a Windows ACL - we're setting the underlying POSIX ACL.
738 *********************************************************************/
739
740 static int sys_acl_set_file_xattr(vfs_handle_struct *handle,
741                               const char *name,
742                               SMB_ACL_TYPE_T type,
743                               SMB_ACL_T theacl)
744 {
745         int ret = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle,
746                                                 name,
747                                                 type,
748                                                 theacl);
749         if (ret == -1) {
750                 return -1;
751         }
752
753         become_root();
754         SMB_VFS_REMOVEXATTR(handle->conn, name, XATTR_NTACL_NAME);
755         unbecome_root();
756
757         return ret;
758 }
759
760 /*********************************************************************
761  Remove a Windows ACL - we're setting the underlying POSIX ACL.
762 *********************************************************************/
763
764 static int sys_acl_set_fd_xattr(vfs_handle_struct *handle,
765                             files_struct *fsp,
766                             SMB_ACL_T theacl)
767 {
768         int ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle,
769                                                 fsp,
770                                                 theacl);
771         if (ret == -1) {
772                 return -1;
773         }
774
775         become_root();
776         SMB_VFS_FREMOVEXATTR(fsp, XATTR_NTACL_NAME);
777         unbecome_root();
778
779         return ret;
780 }
781
782 /* VFS operations structure */
783
784 static vfs_op_tuple skel_op_tuples[] =
785 {
786         {SMB_VFS_OP(mkdir_acl_xattr), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_TRANSPARENT},
787         {SMB_VFS_OP(open_acl_xattr),  SMB_VFS_OP_OPEN,  SMB_VFS_LAYER_TRANSPARENT},
788
789         /* NT File ACL operations */
790
791         {SMB_VFS_OP(fget_nt_acl_xattr),SMB_VFS_OP_FGET_NT_ACL,SMB_VFS_LAYER_TRANSPARENT},
792         {SMB_VFS_OP(get_nt_acl_xattr), SMB_VFS_OP_GET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT},
793         {SMB_VFS_OP(fset_nt_acl_xattr),SMB_VFS_OP_FSET_NT_ACL,SMB_VFS_LAYER_TRANSPARENT},
794
795         /* POSIX ACL operations. */
796         {SMB_VFS_OP(sys_acl_set_file_xattr), SMB_VFS_OP_SYS_ACL_SET_FILE, SMB_VFS_LAYER_TRANSPARENT},
797         {SMB_VFS_OP(sys_acl_set_fd_xattr), SMB_VFS_OP_SYS_ACL_SET_FD, SMB_VFS_LAYER_TRANSPARENT},
798
799         {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
800 };
801
802 NTSTATUS vfs_acl_xattr_init(void)
803 {
804         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "acl_xattr", skel_op_tuples);
805 }