2017-10-18 21:48:37 +03:00
/*
* Copyright ( C ) Ralph Boehme 2017
*
* 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 < http : //www.gnu.org/licenses/>.
*
*/
# include "includes.h"
# include "smbd/proto.h"
# include "libcli/security/security_descriptor.h"
# include "libcli/security/security_token.h"
# include "nfs4_acls.h"
# include "nfs4acl_xattr.h"
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_VFS
# ifdef HAVE_RPC_XDR_H
2018-01-19 16:30:20 +03:00
/* <rpc/xdr.h> uses TRUE and FALSE */
# ifdef TRUE
# undef TRUE
# endif
# ifdef FALSE
# undef FALSE
# endif
2017-10-18 21:48:37 +03:00
# include <rpc/xdr.h>
# include "nfs41acl.h"
# include "nfs4acl_xattr_xdr.h"
2018-11-25 14:07:26 +03:00
# include "nfs4acl_xattr_util.h"
2017-10-18 21:48:37 +03:00
2018-11-25 13:47:48 +03:00
static unsigned nfs4acli_get_naces ( nfsacl41i * nacl )
2017-10-18 21:48:37 +03:00
{
return nacl - > na41_aces . na41_aces_len ;
}
2018-11-25 13:47:48 +03:00
static void nfs4acli_set_naces ( nfsacl41i * nacl , unsigned naces )
2017-10-18 21:48:37 +03:00
{
nacl - > na41_aces . na41_aces_len = naces ;
}
2018-11-25 13:47:48 +03:00
static unsigned nfs4acli_get_flags ( nfsacl41i * nacl )
2017-10-18 21:48:37 +03:00
{
return nacl - > na41_flag ;
}
2018-11-25 13:47:48 +03:00
static void nfs4acli_set_flags ( nfsacl41i * nacl , unsigned flags )
2017-10-18 21:48:37 +03:00
{
nacl - > na41_flag = flags ;
}
2018-11-25 13:47:48 +03:00
static size_t nfs4acli_get_xdrblob_size ( nfsacl41i * nacl )
2017-10-18 21:48:37 +03:00
{
size_t acl_size ;
size_t aces_size ;
2018-11-25 13:47:48 +03:00
unsigned naces = nfs4acli_get_naces ( nacl ) ;
2017-10-18 21:48:37 +03:00
acl_size = sizeof ( aclflag4 ) + sizeof ( unsigned ) ;
if ( naces > NFS4ACL_XDR_MAX_ACES ) {
DBG_ERR ( " Too many ACEs: %u " , naces ) ;
return 0 ;
}
2018-11-22 20:27:47 +03:00
aces_size = naces * sizeof ( struct nfsace4i ) ;
2017-10-18 21:48:37 +03:00
if ( acl_size + aces_size < acl_size ) {
return 0 ;
}
acl_size + = aces_size ;
return acl_size ;
}
2018-11-25 13:47:48 +03:00
static size_t nfs4acli_get_xdrblob_naces ( size_t _blobsize )
2017-10-18 21:48:37 +03:00
{
size_t blobsize = _blobsize ;
blobsize - = sizeof ( aclflag4 ) ;
blobsize - = sizeof ( unsigned ) ;
if ( blobsize > _blobsize ) {
return 0 ;
}
2018-11-22 20:27:47 +03:00
return ( blobsize / sizeof ( struct nfsace4i ) ) ;
2017-10-18 21:48:37 +03:00
}
2018-11-25 13:47:48 +03:00
static nfsacl41i * nfs4acli_alloc ( TALLOC_CTX * mem_ctx , unsigned naces )
2017-10-18 21:48:37 +03:00
{
2018-11-22 20:27:47 +03:00
size_t acl_size = sizeof ( nfsacl41i ) + ( naces * sizeof ( struct nfsace4i ) ) ;
nfsacl41i * nacl = NULL ;
2017-10-18 21:48:37 +03:00
if ( naces > NFS4ACL_XDR_MAX_ACES ) {
DBG_ERR ( " Too many ACEs: %d \n " , naces ) ;
return NULL ;
}
nacl = talloc_zero_size ( mem_ctx , acl_size ) ;
if ( nacl = = NULL ) {
DBG_ERR ( " talloc_zero_size failed \n " ) ;
return NULL ;
}
2018-11-25 13:47:48 +03:00
nfs4acli_set_naces ( nacl , naces ) ;
2017-10-18 21:48:37 +03:00
nacl - > na41_aces . na41_aces_val =
2018-11-22 20:27:47 +03:00
( nfsace4i * ) ( ( char * ) nacl + sizeof ( nfsacl41i ) ) ;
2017-10-18 21:48:37 +03:00
return nacl ;
}
2018-11-25 13:47:48 +03:00
static nfsace4i * nfs4acli_get_ace ( nfsacl41i * nacl , size_t n )
2017-10-18 21:48:37 +03:00
{
return & nacl - > na41_aces . na41_aces_val [ n ] ;
}
2018-11-25 13:47:48 +03:00
static bool smb4acl_to_nfs4acli ( vfs_handle_struct * handle ,
TALLOC_CTX * mem_ctx ,
struct SMB4ACL_T * smb4acl ,
nfsacl41i * * _nacl )
2017-10-18 21:48:37 +03:00
{
struct nfs4acl_config * config = NULL ;
struct SMB4ACE_T * smb4ace = NULL ;
size_t smb4naces = 0 ;
2018-11-22 20:27:47 +03:00
nfsacl41i * nacl = NULL ;
2017-10-18 21:48:37 +03:00
uint16_t smb4acl_flags = 0 ;
unsigned nacl_flags = 0 ;
SMB_VFS_HANDLE_GET_DATA ( handle , config ,
struct nfs4acl_config ,
return false ) ;
smb4naces = smb_get_naces ( smb4acl ) ;
2018-11-25 13:47:48 +03:00
nacl = nfs4acli_alloc ( mem_ctx , smb4naces ) ;
nfs4acli_set_naces ( nacl , 0 ) ;
2017-10-18 21:48:37 +03:00
if ( config - > nfs_version > ACL4_XATTR_VERSION_40 ) {
smb4acl_flags = smbacl4_get_controlflags ( smb4acl ) ;
nacl_flags = smb4acl_to_nfs4acl_flags ( smb4acl_flags ) ;
2018-11-25 13:47:48 +03:00
nfs4acli_set_flags ( nacl , nacl_flags ) ;
2017-10-18 21:48:37 +03:00
}
smb4ace = smb_first_ace4 ( smb4acl ) ;
while ( smb4ace ! = NULL ) {
SMB_ACE4PROP_T * ace4prop = smb_get_ace4 ( smb4ace ) ;
2018-11-25 13:47:48 +03:00
size_t nace_count = nfs4acli_get_naces ( nacl ) ;
nfsace4i * nace = nfs4acli_get_ace ( nacl , nace_count ) ;
2017-10-18 21:48:37 +03:00
nace - > type = ace4prop - > aceType ;
nace - > flag = ace4prop - > aceFlags ;
nace - > access_mask = ace4prop - > aceMask ;
if ( ace4prop - > flags & SMB_ACE4_ID_SPECIAL ) {
nace - > iflag | = ACEI4_SPECIAL_WHO ;
switch ( ace4prop - > who . special_id ) {
case SMB_ACE4_WHO_OWNER :
nace - > who = ACE4_SPECIAL_OWNER ;
break ;
case SMB_ACE4_WHO_GROUP :
nace - > who = ACE4_SPECIAL_GROUP ;
break ;
case SMB_ACE4_WHO_EVERYONE :
nace - > who = ACE4_SPECIAL_EVERYONE ;
break ;
default :
DBG_ERR ( " Unsupported special id [%d] \n " ,
ace4prop - > who . special_id ) ;
continue ;
}
} else {
if ( ace4prop - > aceFlags & SMB_ACE4_IDENTIFIER_GROUP ) {
nace - > flag | = ACE4_IDENTIFIER_GROUP ;
nace - > who = ace4prop - > who . gid ;
} else {
nace - > who = ace4prop - > who . uid ;
}
}
nace_count + + ;
2018-11-25 13:47:48 +03:00
nfs4acli_set_naces ( nacl , nace_count ) ;
2017-10-18 21:48:37 +03:00
smb4ace = smb_next_ace4 ( smb4ace ) ;
}
* _nacl = nacl ;
return true ;
}
NTSTATUS nfs4acl_smb4acl_to_xdr_blob ( vfs_handle_struct * handle ,
TALLOC_CTX * mem_ctx ,
struct SMB4ACL_T * smb4acl ,
DATA_BLOB * _blob )
{
2018-11-22 20:27:47 +03:00
nfsacl41i * nacl = NULL ;
2017-10-18 21:48:37 +03:00
XDR xdr = { 0 } ;
size_t aclblobsize ;
DATA_BLOB blob ;
bool ok ;
2018-11-25 13:47:48 +03:00
ok = smb4acl_to_nfs4acli ( handle , talloc_tos ( ) , smb4acl , & nacl ) ;
2017-10-18 21:48:37 +03:00
if ( ! ok ) {
DBG_ERR ( " smb4acl_to_nfs4acl failed \n " ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
2018-11-25 13:47:48 +03:00
aclblobsize = nfs4acli_get_xdrblob_size ( nacl ) ;
2017-10-18 21:48:37 +03:00
if ( aclblobsize = = 0 ) {
return NT_STATUS_INTERNAL_ERROR ;
}
blob = data_blob_talloc ( mem_ctx , NULL , aclblobsize ) ;
if ( blob . data = = NULL ) {
TALLOC_FREE ( nacl ) ;
return NT_STATUS_NO_MEMORY ;
}
xdrmem_create ( & xdr , ( char * ) blob . data , blob . length , XDR_ENCODE ) ;
2018-11-22 20:27:47 +03:00
ok = xdr_nfsacl41i ( & xdr , nacl ) ;
2017-10-18 21:48:37 +03:00
TALLOC_FREE ( nacl ) ;
if ( ! ok ) {
DBG_ERR ( " xdr_nfs4acl41 failed \n " ) ;
return NT_STATUS_NO_MEMORY ;
}
* _blob = blob ;
return NT_STATUS_OK ;
}
2018-11-25 13:47:48 +03:00
static NTSTATUS nfs4acl_xdr_blob_to_nfs4acli ( struct vfs_handle_struct * handle ,
TALLOC_CTX * mem_ctx ,
DATA_BLOB * blob ,
nfsacl41i * * _nacl )
2017-10-18 21:48:37 +03:00
{
struct nfs4acl_config * config = NULL ;
2018-11-22 20:27:47 +03:00
nfsacl41i * nacl = NULL ;
2017-10-18 21:48:37 +03:00
size_t naces ;
XDR xdr = { 0 } ;
bool ok ;
SMB_VFS_HANDLE_GET_DATA ( handle , config ,
struct nfs4acl_config ,
return NT_STATUS_INTERNAL_ERROR ) ;
2018-11-25 13:47:48 +03:00
naces = nfs4acli_get_xdrblob_naces ( blob - > length ) ;
nacl = nfs4acli_alloc ( mem_ctx , naces ) ;
2017-10-18 21:48:37 +03:00
xdrmem_create ( & xdr , ( char * ) blob - > data , blob - > length , XDR_DECODE ) ;
2018-11-22 20:27:47 +03:00
ok = xdr_nfsacl41i ( & xdr , nacl ) ;
2017-10-18 21:48:37 +03:00
if ( ! ok ) {
DBG_ERR ( " xdr_nfs4acl41 failed \n " ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
if ( config - > nfs_version = = ACL4_XATTR_VERSION_40 ) {
nacl - > na41_flag = 0 ;
}
* _nacl = nacl ;
return NT_STATUS_OK ;
}
2018-11-25 13:47:48 +03:00
static NTSTATUS nfs4acli_to_smb4acl ( struct vfs_handle_struct * handle ,
TALLOC_CTX * mem_ctx ,
nfsacl41i * nacl ,
struct SMB4ACL_T * * _smb4acl )
2017-10-18 21:48:37 +03:00
{
struct nfs4acl_config * config = NULL ;
struct SMB4ACL_T * smb4acl = NULL ;
unsigned nfsacl41_flag = 0 ;
uint16_t smb4acl_flags = 0 ;
2018-11-25 13:47:48 +03:00
unsigned naces = nfs4acli_get_naces ( nacl ) ;
2017-10-18 21:48:37 +03:00
int i ;
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 ;
}
if ( config - > nfs_version > ACL4_XATTR_VERSION_40 ) {
2018-11-25 13:47:48 +03:00
nfsacl41_flag = nfs4acli_get_flags ( nacl ) ;
2017-10-18 21:48:37 +03:00
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 + + ) {
2018-11-25 13:47:48 +03:00
nfsace4i * nace = nfs4acli_get_ace ( nacl , i ) ;
2017-10-18 21:48:37 +03:00
SMB_ACE4PROP_T smbace = { 0 } ;
DBG_DEBUG ( " type [%d] iflag [%x] flag [%x] mask [%x] who [%d] \n " ,
nace - > type , nace - > iflag , nace - > flag ,
nace - > access_mask , nace - > who ) ;
smbace . aceType = nace - > type ;
smbace . aceFlags = nace - > flag ;
smbace . aceMask = nace - > access_mask ;
if ( nace - > iflag & ACEI4_SPECIAL_WHO ) {
smbace . flags | = SMB_ACE4_ID_SPECIAL ;
switch ( nace - > who ) {
case ACE4_SPECIAL_OWNER :
smbace . who . special_id = SMB_ACE4_WHO_OWNER ;
break ;
case ACE4_SPECIAL_GROUP :
smbace . who . special_id = SMB_ACE4_WHO_GROUP ;
break ;
case ACE4_SPECIAL_EVERYONE :
smbace . who . special_id = SMB_ACE4_WHO_EVERYONE ;
break ;
default :
DBG_ERR ( " Unknown special id [%d] \n " , nace - > who ) ;
continue ;
}
} else {
if ( nace - > flag & ACE4_IDENTIFIER_GROUP ) {
smbace . who . gid = nace - > who ;
} else {
smbace . who . uid = nace - > who ;
}
}
smb_add_ace4 ( smb4acl , & smbace ) ;
}
* _smb4acl = smb4acl ;
return NT_STATUS_OK ;
}
NTSTATUS nfs4acl_xdr_blob_to_smb4 ( struct vfs_handle_struct * handle ,
TALLOC_CTX * mem_ctx ,
DATA_BLOB * blob ,
struct SMB4ACL_T * * _smb4acl )
{
struct nfs4acl_config * config = NULL ;
2018-11-22 20:27:47 +03:00
nfsacl41i * nacl = NULL ;
2017-10-18 21:48:37 +03:00
struct SMB4ACL_T * smb4acl = NULL ;
NTSTATUS status ;
SMB_VFS_HANDLE_GET_DATA ( handle , config ,
struct nfs4acl_config ,
return NT_STATUS_INTERNAL_ERROR ) ;
2018-11-25 13:47:48 +03:00
status = nfs4acl_xdr_blob_to_nfs4acli ( handle , talloc_tos ( ) , blob , & nacl ) ;
2017-10-18 21:48:37 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2018-11-25 13:47:48 +03:00
status = nfs4acli_to_smb4acl ( handle , mem_ctx , nacl , & smb4acl ) ;
2017-10-18 21:48:37 +03:00
TALLOC_FREE ( nacl ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
* _smb4acl = smb4acl ;
return NT_STATUS_OK ;
}
# else /* !HAVE_RPC_XDR_H */
2017-11-19 08:18:03 +03:00
# include "nfs4acl_xattr_xdr.h"
2017-10-18 21:48:37 +03:00
NTSTATUS nfs4acl_xdr_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_xdr_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 */