/* * Copyright (C) Ralph Boehme 2018 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * */ #include "includes.h" #include "smbd/proto.h" #include "system/passwd.h" #include "libcli/security/security_descriptor.h" #include "libcli/security/security_token.h" #ifdef HAVE_RPC_XDR_H /* uses TRUE and FALSE */ #ifdef TRUE #undef TRUE #endif #ifdef FALSE #undef FALSE #endif #ifdef HAVE_RPC_TYPES_H #include #endif #include #include "nfs4_acls.h" #include "nfs41acl.h" #include "nfs4acl_xattr.h" #include "nfs4acl_xattr_nfs.h" #include "nfs4acl_xattr_util.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_VFS #define OVERFLOW_CHECK(val1, val2) ((val1) + (val2) < (val1)) #define XDR_UTF8STR_ALIGNMENT 4 #define XDR_UTF8STR_ALIGN(l) \ (((l) + ((XDR_UTF8STR_ALIGNMENT) - 1)) & ~((XDR_UTF8STR_ALIGNMENT) - 1)) static struct nfs4_to_smb4_id_map { const char *nfs4_id; uint32_t smb4_id; } nfs4_to_smb4_id_map[] = { {"OWNER@", SMB_ACE4_WHO_OWNER}, {"GROUP@", SMB_ACE4_WHO_GROUP}, {"EVERYONE@", SMB_ACE4_WHO_EVERYONE}, {"INTERACTIVE@", SMB_ACE4_WHO_INTERACTIVE}, {"NETWORK@", SMB_ACE4_WHO_NETWORK}, {"DIALUP@", SMB_ACE4_WHO_DIALUP}, {"BATCH@", SMB_ACE4_WHO_BATCH}, {"ANONYMOUS@", SMB_ACE4_WHO_ANONYMOUS}, {"AUTHENTICATED@", SMB_ACE4_WHO_AUTHENTICATED}, {"SERVICE@", SMB_ACE4_WHO_SERVICE}, }; static bool is_special_nfs4_id(const char *nfs4_id) { char *at = NULL; at = strchr(nfs4_id, '@'); if (at == NULL) { return false; } if (at[1] != '\0') { return false; } return true; } static bool map_special_nfs4_to_smb4_id(const char *nfs4_id, uint32_t *smb4_id) { size_t i; int cmp; for (i = 0; i < ARRAY_SIZE(nfs4_to_smb4_id_map); i++) { cmp = strcmp(nfs4_to_smb4_id_map[i].nfs4_id, nfs4_id); if (cmp != 0) { continue; } *smb4_id = nfs4_to_smb4_id_map[i].smb4_id; return true; } return false; } static bool map_special_smb4_to_nfs4_id(uint32_t smb4_id, const char **nfs4_id) { size_t i; for (i = 0; i < ARRAY_SIZE(nfs4_to_smb4_id_map); i++) { if (nfs4_to_smb4_id_map[i].smb4_id != smb4_id) { continue; } *nfs4_id = nfs4_to_smb4_id_map[i].nfs4_id; return true; } return false; } static unsigned nfs40acl_get_naces(nfsacl40 *nacl) { return nacl->na40_aces.na40_aces_len; } static unsigned nfs41acl_get_naces(nfsacl41 *nacl) { return nacl->na41_aces.na41_aces_len; } static void nfs40acl_set_naces(nfsacl40 *nacl, unsigned naces) { nacl->na40_aces.na40_aces_len = naces; } static void nfs41acl_set_naces(nfsacl41 *nacl, unsigned naces) { nacl->na41_aces.na41_aces_len = naces; } static unsigned nfs41acl_get_flags(nfsacl41 *nacl) { return nacl->na41_flag; } static void nfs41acl_set_flags(nfsacl41 *nacl, unsigned flags) { nacl->na41_flag = flags; } static nfsace4 *nfs40acl_get_ace(nfsacl40 *nacl, size_t n) { return &nacl->na40_aces.na40_aces_val[n]; } static nfsace4 *nfs41acl_get_ace(nfsacl41 *nacl, size_t n) { return &nacl->na41_aces.na41_aces_val[n]; } static size_t nfs40acl_get_xdrblob_size(nfsacl40 *nacl) { size_t acl_size; size_t aces_size; size_t identifier_size; unsigned i; unsigned naces = nfs40acl_get_naces(nacl); /* ACE structure minus actual identifier strings */ struct nfsace4_size { acetype4 type; aceflag4 flag; acemask4 access_mask; u_int who_length; }; /* * acl_size = * sizeof(ace_count) + * (ace_count * (sizeof(nfsace4_size)) + * length of all identifiers strings */ acl_size = sizeof(unsigned); if (naces > NFS4ACL_XDR_MAX_ACES) { DBG_ERR("Too many ACEs: %u", naces); return 0; } aces_size = naces * sizeof(struct nfsace4_size); if (OVERFLOW_CHECK(acl_size, aces_size)) { DBG_ERR("Integer Overflow error\n"); return 0; } acl_size += aces_size; identifier_size = 0; for (i = 0; i < naces; i++) { nfsace4 *nace = nfs40acl_get_ace(nacl, i); size_t string_size = nace->who.utf8string_len; size_t id_size; id_size = XDR_UTF8STR_ALIGN(string_size); if (OVERFLOW_CHECK(identifier_size, id_size)) { DBG_ERR("Integer Overflow error\n"); return 0; } identifier_size += id_size; } if (OVERFLOW_CHECK(acl_size, identifier_size)) { DBG_ERR("Integer Overflow error\n"); return 0; } acl_size += identifier_size; DBG_DEBUG("acl_size: %zd\n", acl_size); return acl_size; } static size_t nfs41acl_get_xdrblob_size(nfsacl41 *nacl) { size_t acl_size; size_t aces_size; size_t identifier_size; unsigned i; unsigned naces = nfs41acl_get_naces(nacl); /* ACE structure minus actual identifier strings */ struct nfsace4_size { acetype4 type; aceflag4 flag; acemask4 access_mask; u_int who_length; }; /* * acl_size = * sizeof(acl_flag) + * sizeof(ace_count) + * (ace_count * (sizeof(nfsace4_size)) + * length of all identifiers strings */ acl_size = 2 * sizeof(unsigned); if (naces > NFS4ACL_XDR_MAX_ACES) { DBG_ERR("Too many ACEs: %u", naces); return 0; } aces_size = naces * sizeof(struct nfsace4_size); if (OVERFLOW_CHECK(acl_size, aces_size)) { DBG_ERR("Integer Overflow error\n"); return 0; } acl_size += aces_size; identifier_size = 0; for (i = 0; i < naces; i++) { nfsace4 *nace = nfs41acl_get_ace(nacl, i); size_t string_size = nace->who.utf8string_len; size_t id_size; id_size = XDR_UTF8STR_ALIGN(string_size); if (OVERFLOW_CHECK(identifier_size, id_size)) { DBG_ERR("Integer Overflow error\n"); return 0; } identifier_size += id_size; } if (OVERFLOW_CHECK(acl_size, identifier_size)) { DBG_ERR("Integer Overflow error\n"); return 0; } acl_size += identifier_size; DBG_DEBUG("acl_size: %zd\n", acl_size); return acl_size; } static nfsacl40 *nfs40acl_alloc(TALLOC_CTX *mem_ctx, unsigned naces) { size_t acl_size; size_t aces_size; nfsacl40 *nacl = NULL; if (naces > NFS4ACL_XDR_MAX_ACES) { DBG_ERR("Too many ACEs: %d\n", naces); return NULL; } acl_size = sizeof(nfsacl40); aces_size = (naces * sizeof(struct nfsace4)); if (OVERFLOW_CHECK(acl_size, aces_size)) { DBG_ERR("Integer Overflow error\n"); return NULL; } acl_size += aces_size; nacl = talloc_zero_size(mem_ctx, acl_size); if (nacl == NULL) { DBG_ERR("talloc_zero_size failed\n"); return NULL; } nfs40acl_set_naces(nacl, naces); nacl->na40_aces.na40_aces_val = (nfsace4 *)((uint8_t *)nacl + sizeof(nfsacl40)); return nacl; } static nfsacl41 *nfs41acl_alloc(TALLOC_CTX *mem_ctx, unsigned naces) { size_t acl_size; size_t aces_size; nfsacl41 *nacl = NULL; if (naces > NFS4ACL_XDR_MAX_ACES) { DBG_ERR("Too many ACEs: %d\n", naces); return NULL; } acl_size = sizeof(nfsacl41); aces_size = (naces * sizeof(struct nfsace4)); if (OVERFLOW_CHECK(acl_size, aces_size)) { DBG_ERR("Integer Overflow error\n"); return NULL; } acl_size += aces_size; nacl = talloc_zero_size(mem_ctx, acl_size); if (nacl == NULL) { DBG_ERR("talloc_zero_size failed\n"); return NULL; } nfs41acl_set_naces(nacl, naces); nacl->na41_aces.na41_aces_val = (nfsace4 *)((uint8_t *)nacl + sizeof(nfsacl41)); return nacl; } static bool create_special_id(TALLOC_CTX *mem_ctx, nfsace4 *nace, const char *id) { char *s = talloc_strdup(mem_ctx, id); if (s == NULL) { DBG_ERR("talloc_strdup failed\n"); return false; } nace->who.utf8string_val = s; nace->who.utf8string_len = talloc_get_size(s) - 1; return true; } static bool map_smb4_to_nfs4_id(TALLOC_CTX *mem_ctx, struct nfs4acl_config *config, nfsace4 *nace, SMB_ACE4PROP_T *sace) { const char *nfs4_id = NULL; const char *name = NULL; char *ace_name = NULL; uid_t id; bool ok; if (sace->flags & SMB_ACE4_ID_SPECIAL) { ok = map_special_smb4_to_nfs4_id(sace->who.special_id, &nfs4_id); if (!ok) { DBG_ERR("Unsupported special id [%"PRIu32"]\n", sace->who.special_id); return false; } ok = create_special_id(mem_ctx, nace, nfs4_id); if (!ok) { return false; } DBG_DEBUG("Special id [%s]\n", nace->who.utf8string_val); return true; } if (sace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) { nace->flag |= ACE4_IDENTIFIER_GROUP; } if (config->nfs4_id_numeric) { char *strid = NULL; if (sace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) { id = sace->who.gid; } else { id = sace->who.uid; } strid = talloc_asprintf(mem_ctx, "%jd", (intmax_t)id); if (strid == NULL) { DBG_ERR("talloc_asprintf failed\n"); return false; } nace->who.utf8string_val = strid; nace->who.utf8string_len = talloc_get_size(strid) - 1; DBG_DEBUG("Numeric id [%s]\n", nace->who.utf8string_val); return true; } if (sace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) { struct group *grp = NULL; grp = getgrgid(sace->who.gid); if (grp == NULL) { DBG_ERR("Unknown gid [%jd]\n", (intmax_t)sace->who.gid); return false; } name = grp->gr_name; } else { struct passwd *pwd = NULL; pwd = getpwuid(sace->who.uid); if (pwd == NULL) { DBG_ERR("Unknown uid [%jd]\n", (intmax_t)sace->who.uid); return false; } name = pwd->pw_name; } ace_name = talloc_strdup(mem_ctx, name); if (ace_name == NULL) { DBG_ERR("talloc_asprintf failed\n"); return false; } nace->who.utf8string_val = ace_name; nace->who.utf8string_len = talloc_get_size(ace_name) - 1; DBG_DEBUG("id [%s]\n", nace->who.utf8string_val); return true; } static bool smb4acl_to_nfs40acl(vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, struct SMB4ACL_T *smb4acl, nfsacl40 **_nacl) { struct nfs4acl_config *config = NULL; struct SMB4ACE_T *smb4ace = NULL; nfsacl40 *nacl = NULL; size_t naces = smb_get_naces(smb4acl); bool ok; SMB_VFS_HANDLE_GET_DATA(handle, config, struct nfs4acl_config, return false); nacl = nfs40acl_alloc(mem_ctx, naces); nfs40acl_set_naces(nacl, 0); smb4ace = smb_first_ace4(smb4acl); while (smb4ace != NULL) { SMB_ACE4PROP_T *ace4prop = smb_get_ace4(smb4ace); size_t nace_count = nfs40acl_get_naces(nacl); nfsace4 *nace = nfs40acl_get_ace(nacl, nace_count); nace->type = ace4prop->aceType; nace->flag = ace4prop->aceFlags; nace->access_mask = ace4prop->aceMask; ok = map_smb4_to_nfs4_id(nacl, config, nace, ace4prop); if (!ok) { smb4ace = smb_next_ace4(smb4ace); continue; } nace_count++; nfs40acl_set_naces(nacl, nace_count); smb4ace = smb_next_ace4(smb4ace); } *_nacl = nacl; return true; } static bool smb4acl_to_nfs41acl(vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, struct SMB4ACL_T *smb4acl, nfsacl41 **_nacl) { struct nfs4acl_config *config = NULL; struct SMB4ACE_T *smb4ace = NULL; nfsacl41 *nacl = NULL; size_t naces = smb_get_naces(smb4acl); uint16_t smb4acl_flags; unsigned nacl_flags; bool ok; SMB_VFS_HANDLE_GET_DATA(handle, config, struct nfs4acl_config, return false); nacl = nfs41acl_alloc(mem_ctx, naces); nfs41acl_set_naces(nacl, 0); smb4acl_flags = smbacl4_get_controlflags(smb4acl); nacl_flags = smb4acl_to_nfs4acl_flags(smb4acl_flags); nfs41acl_set_flags(nacl, nacl_flags); smb4ace = smb_first_ace4(smb4acl); while (smb4ace != NULL) { SMB_ACE4PROP_T *ace4prop = smb_get_ace4(smb4ace); size_t nace_count = nfs41acl_get_naces(nacl); nfsace4 *nace = nfs41acl_get_ace(nacl, nace_count); nace->type = ace4prop->aceType; nace->flag = ace4prop->aceFlags; nace->access_mask = ace4prop->aceMask; ok = map_smb4_to_nfs4_id(nacl, config, nace, ace4prop); if (!ok) { smb4ace = smb_next_ace4(smb4ace); continue; } nace_count++; nfs41acl_set_naces(nacl, nace_count); smb4ace = smb_next_ace4(smb4ace); } *_nacl = nacl; return true; } NTSTATUS nfs4acl_smb4acl_to_nfs_blob(vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, struct SMB4ACL_T *smb4acl, DATA_BLOB *_blob) { struct nfs4acl_config *config = NULL; nfsacl40 *nacl40 = NULL; nfsacl41 *nacl41 = NULL; XDR xdr = {0}; size_t aclblobsize; DATA_BLOB blob; bool ok; SMB_VFS_HANDLE_GET_DATA(handle, config, struct nfs4acl_config, return NT_STATUS_INTERNAL_ERROR); if (config->nfs_version == ACL4_XATTR_VERSION_40) { ok = smb4acl_to_nfs40acl(handle, mem_ctx, smb4acl, &nacl40); if (!ok) { DBG_ERR("smb4acl_to_nfs4acl failed\n"); return NT_STATUS_INTERNAL_ERROR; } aclblobsize = nfs40acl_get_xdrblob_size(nacl40); if (aclblobsize == 0) { DBG_ERR("Error calculating XDR blob size\n"); return NT_STATUS_INTERNAL_ERROR; } } else { ok = smb4acl_to_nfs41acl(handle, mem_ctx, smb4acl, &nacl41); if (!ok) { DBG_ERR("smb4acl_to_nfs4acl failed\n"); return NT_STATUS_INTERNAL_ERROR; } aclblobsize = nfs41acl_get_xdrblob_size(nacl41); if (aclblobsize == 0) { DBG_ERR("Error calculating XDR blob size\n"); return NT_STATUS_INTERNAL_ERROR; } } blob = data_blob_talloc(mem_ctx, NULL, aclblobsize); if (blob.data == NULL) { TALLOC_FREE(nacl40); TALLOC_FREE(nacl41); return NT_STATUS_NO_MEMORY; } xdrmem_create(&xdr, (char *)blob.data, blob.length, XDR_ENCODE); if (config->nfs_version == ACL4_XATTR_VERSION_40) { ok = xdr_nfsacl40(&xdr, nacl40); TALLOC_FREE(nacl40); if (!ok) { DBG_ERR("xdr_nfs4acl40 failed\n"); return NT_STATUS_NO_MEMORY; } } else { ok = xdr_nfsacl41(&xdr, nacl41); TALLOC_FREE(nacl41); if (!ok) { DBG_ERR("xdr_nfs4acl40 failed\n"); return NT_STATUS_NO_MEMORY; } } *_blob = blob; return NT_STATUS_OK; } static NTSTATUS nfs4acl_nfs_blob_to_nfs40acl(struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, DATA_BLOB *blob, nfsacl40 **_nacl) { nfsacl40 *nacl = NULL; XDR xdr = {0}; bool ok; nacl = talloc_zero_size(mem_ctx, sizeof(nfsacl40)); if (nacl == NULL) { DBG_ERR("talloc_zero_size failed\n"); return NT_STATUS_NO_MEMORY; } xdrmem_create(&xdr, (char *)blob->data, blob->length, XDR_DECODE); ok = xdr_nfsacl40(&xdr, nacl); if (!ok) { DBG_ERR("xdr_nfsacl40 failed\n"); return NT_STATUS_INTERNAL_ERROR; } DBG_DEBUG("naces = %d \n", nacl->na40_aces.na40_aces_len); *_nacl = nacl; return NT_STATUS_OK; } static NTSTATUS nfs4acl_nfs_blob_to_nfs41acl(struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, DATA_BLOB *blob, nfsacl41 **_nacl) { nfsacl41 *nacl = NULL; XDR xdr = {0}; bool ok; nacl = talloc_zero_size(mem_ctx, sizeof(nfsacl41)); if (nacl == NULL) { DBG_ERR("talloc_zero_size failed\n"); return NT_STATUS_NO_MEMORY; } xdrmem_create(&xdr, (char *)blob->data, blob->length, XDR_DECODE); ok = xdr_nfsacl41(&xdr, nacl); if (!ok) { DBG_ERR("xdr_nfsacl40 failed\n"); return NT_STATUS_INTERNAL_ERROR; } DBG_DEBUG("naces = %d \n", nacl->na41_aces.na41_aces_len); *_nacl = nacl; return NT_STATUS_OK; } static bool map_ace_nfs4_to_smb4(struct nfs4acl_config *config, const nfsace4 *nace, SMB_ACE4PROP_T *sace) { char *name = NULL; char *p = NULL; uint32_t smb4_id; bool ok; name = talloc_strndup(talloc_tos(), nace->who.utf8string_val, nace->who.utf8string_len); if (name == NULL) { return false; } sace->aceType = nace->type; sace->aceFlags = nace->flag; sace->aceMask = nace->access_mask; if (is_special_nfs4_id(name)) { ok = map_special_nfs4_to_smb4_id(name, &smb4_id); if (!ok) { DBG_WARNING("Unknown special id [%s]\n", name); return false; } sace->flags |= SMB_ACE4_ID_SPECIAL; sace->who.special_id = smb4_id; return true; } p = strtok(name, "@"); if (p == NULL && !config->nfs4_id_numeric) { DBG_ERR("Unqualified name [%s]\n", name); TALLOC_FREE(name); return false; } /* * nametouid() and nametogid() work with both names and numbers... */ if (nace->flag & ACE4_IDENTIFIER_GROUP) { sace->who.gid = nametogid(name); if (sace->who.gid == (gid_t)-1) { DBG_ERR("converting id [%s] failed\n", name); TALLOC_FREE(name); return false; } TALLOC_FREE(name); return true; } sace->who.uid = nametouid(name); if (sace->who.uid == (gid_t)-1) { DBG_ERR("converting id [%s] failed\n", name); TALLOC_FREE(name); return false; } TALLOC_FREE(name); return true; } static NTSTATUS nfs40acl_to_smb4acl(struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, nfsacl40 *nacl, struct SMB4ACL_T **_smb4acl) { struct nfs4acl_config *config = NULL; struct SMB4ACL_T *smb4acl = NULL; unsigned naces = nfs40acl_get_naces(nacl); unsigned int i; bool ok; SMB_VFS_HANDLE_GET_DATA(handle, config, struct nfs4acl_config, return NT_STATUS_INTERNAL_ERROR); smb4acl = smb_create_smb4acl(mem_ctx); if (smb4acl == NULL) { return NT_STATUS_INTERNAL_ERROR; } DBG_DEBUG("nace [%u]\n", naces); for (i = 0; i < naces; i++) { nfsace4 *nace = nfs40acl_get_ace(nacl, i); SMB_ACE4PROP_T sace = { 0 }; DBG_DEBUG("type [%d] flag [%x] mask [%x] who [%*s]\n", nace->type, nace->flag, nace->access_mask, nace->who.utf8string_len, nace->who.utf8string_val); ok = map_ace_nfs4_to_smb4(config, nace, &sace); if (!ok) { continue; } smb_add_ace4(smb4acl, &sace); } *_smb4acl = smb4acl; return NT_STATUS_OK; } static NTSTATUS nfs41acl_to_smb4acl(struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, nfsacl41 *nacl, struct SMB4ACL_T **_smb4acl) { struct nfs4acl_config *config = NULL; struct SMB4ACL_T *smb4acl = NULL; unsigned nfsacl41_flag = 0; uint16_t smb4acl_flags = 0; unsigned naces = nfs41acl_get_naces(nacl); unsigned int i; bool ok; SMB_VFS_HANDLE_GET_DATA(handle, config, struct nfs4acl_config, return NT_STATUS_INTERNAL_ERROR); smb4acl = smb_create_smb4acl(mem_ctx); if (smb4acl == NULL) { return NT_STATUS_INTERNAL_ERROR; } nfsacl41_flag = nfs41acl_get_flags(nacl); smb4acl_flags = nfs4acl_to_smb4acl_flags(nfsacl41_flag); smbacl4_set_controlflags(smb4acl, smb4acl_flags); DBG_DEBUG("flags [%x] nace [%u]\n", smb4acl_flags, naces); for (i = 0; i < naces; i++) { nfsace4 *nace = nfs41acl_get_ace(nacl, i); SMB_ACE4PROP_T sace = { 0 }; DBG_DEBUG("type [%d] flag [%x] mask [%x] who [%*s]\n", nace->type, nace->flag, nace->access_mask, nace->who.utf8string_len, nace->who.utf8string_val); ok = map_ace_nfs4_to_smb4(config, nace, &sace); if (!ok) { continue; } smb_add_ace4(smb4acl, &sace); } *_smb4acl = smb4acl; return NT_STATUS_OK; } NTSTATUS nfs4acl_nfs_blob_to_smb4(struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct SMB4ACL_T **_smb4acl) { struct nfs4acl_config *config = NULL; struct SMB4ACL_T *smb4acl = NULL; NTSTATUS status; SMB_VFS_HANDLE_GET_DATA(handle, config, struct nfs4acl_config, return NT_STATUS_INTERNAL_ERROR); if (config->nfs_version == ACL4_XATTR_VERSION_40) { nfsacl40 *nacl = NULL; status = nfs4acl_nfs_blob_to_nfs40acl(handle, talloc_tos(), blob, &nacl); if (!NT_STATUS_IS_OK(status)) { return status; } status = nfs40acl_to_smb4acl(handle, mem_ctx, nacl, &smb4acl); TALLOC_FREE(nacl); if (!NT_STATUS_IS_OK(status)) { return status; } } else { nfsacl41 *nacl = NULL; status = nfs4acl_nfs_blob_to_nfs41acl(handle, talloc_tos(), blob, &nacl); if (!NT_STATUS_IS_OK(status)) { return status; } status = nfs41acl_to_smb4acl(handle, mem_ctx, nacl, &smb4acl); TALLOC_FREE(nacl); if (!NT_STATUS_IS_OK(status)) { return status; } } *_smb4acl = smb4acl; return NT_STATUS_OK; } #else /* !HAVE_RPC_XDR_H */ #include "nfs4acl_xattr_nfs.h" NTSTATUS nfs4acl_nfs_blob_to_smb4(struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct SMB4ACL_T **_smb4acl) { return NT_STATUS_NOT_SUPPORTED; } NTSTATUS nfs4acl_smb4acl_to_nfs_blob(vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, struct SMB4ACL_T *smbacl, DATA_BLOB *blob) { return NT_STATUS_NOT_SUPPORTED; } #endif /* HAVE_RPC_XDR_H */