2004-11-05 10:29:02 +03:00
/*
Unix SMB / CIFS implementation .
POSIX NTVFS backend - xattr support
Copyright ( C ) Andrew Tridgell 2004
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 2 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 , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
# include "vfs_posix.h"
2006-03-07 17:34:32 +03:00
# include "util/unix_privs.h"
2004-11-05 10:29:02 +03:00
/*
2004-12-17 06:39:29 +03:00
pull a xattr as a blob
2004-11-05 10:29:02 +03:00
*/
2004-11-13 08:47:27 +03:00
static NTSTATUS pull_xattr_blob ( struct pvfs_state * pvfs ,
TALLOC_CTX * mem_ctx ,
2004-11-05 10:29:02 +03:00
const char * attr_name ,
const char * fname ,
int fd ,
size_t estimated_size ,
DATA_BLOB * blob )
{
2004-12-19 02:31:17 +03:00
NTSTATUS status ;
2004-12-17 06:39:29 +03:00
if ( pvfs - > ea_db ) {
return pull_xattr_blob_tdb ( pvfs , mem_ctx , attr_name , fname ,
fd , estimated_size , blob ) ;
2004-11-05 10:29:02 +03:00
}
2004-12-19 02:31:17 +03:00
status = pull_xattr_blob_system ( pvfs , mem_ctx , attr_name , fname ,
fd , estimated_size , blob ) ;
/* if the filesystem doesn't support them, then tell pvfs not to try again */
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_SUPPORTED ) ) {
DEBUG ( 5 , ( " pvfs_xattr: xattr not supported in filesystem \n " ) ) ;
pvfs - > flags & = ~ PVFS_FLAG_XATTR_ENABLE ;
status = NT_STATUS_NOT_FOUND ;
}
return status ;
2004-11-05 10:29:02 +03:00
}
/*
2004-12-17 06:39:29 +03:00
push a xattr as a blob
2004-11-05 10:29:02 +03:00
*/
2004-11-13 08:47:27 +03:00
static NTSTATUS push_xattr_blob ( struct pvfs_state * pvfs ,
const char * attr_name ,
2004-11-05 10:29:02 +03:00
const char * fname ,
int fd ,
const DATA_BLOB * blob )
{
2004-12-17 06:39:29 +03:00
if ( pvfs - > ea_db ) {
return push_xattr_blob_tdb ( pvfs , attr_name , fname , fd , blob ) ;
2004-11-05 10:29:02 +03:00
}
2004-12-17 06:39:29 +03:00
return push_xattr_blob_system ( pvfs , attr_name , fname , fd , blob ) ;
2004-11-05 10:29:02 +03:00
}
2004-11-17 08:58:04 +03:00
/*
delete a xattr
*/
static NTSTATUS delete_xattr ( struct pvfs_state * pvfs , const char * attr_name ,
const char * fname , int fd )
{
2004-12-17 06:39:29 +03:00
if ( pvfs - > ea_db ) {
return delete_xattr_tdb ( pvfs , attr_name , fname , fd ) ;
2004-11-17 08:58:04 +03:00
}
2004-12-17 06:39:29 +03:00
return delete_xattr_system ( pvfs , attr_name , fname , fd ) ;
}
2004-11-17 08:58:04 +03:00
2004-12-17 06:39:29 +03:00
/*
a hook called on unlink - allows the tdb xattr backend to cleanup
*/
NTSTATUS pvfs_xattr_unlink_hook ( struct pvfs_state * pvfs , const char * fname )
{
if ( pvfs - > ea_db ) {
return unlink_xattr_tdb ( pvfs , fname ) ;
}
return unlink_xattr_system ( pvfs , fname ) ;
2004-11-17 08:58:04 +03:00
}
2004-12-17 06:39:29 +03:00
2004-11-05 14:31:35 +03:00
/*
load a NDR structure from a xattr
*/
2004-11-13 08:47:27 +03:00
static NTSTATUS pvfs_xattr_ndr_load ( struct pvfs_state * pvfs ,
TALLOC_CTX * mem_ctx ,
2004-11-05 14:31:35 +03:00
const char * fname , int fd , const char * attr_name ,
void * p , ndr_pull_flags_fn_t pull_fn )
{
NTSTATUS status ;
DATA_BLOB blob ;
2004-11-13 08:47:27 +03:00
status = pull_xattr_blob ( pvfs , mem_ctx , attr_name , fname ,
2004-11-05 14:31:35 +03:00
fd , XATTR_DOSATTRIB_ESTIMATED_SIZE , & blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/* pull the blob */
status = ndr_pull_struct_blob ( & blob , mem_ctx , p , pull_fn ) ;
data_blob_free ( & blob ) ;
return status ;
}
2004-11-05 10:29:02 +03:00
/*
2004-11-05 14:31:35 +03:00
save a NDR structure into a xattr
2004-11-05 10:29:02 +03:00
*/
2004-11-13 08:47:27 +03:00
static NTSTATUS pvfs_xattr_ndr_save ( struct pvfs_state * pvfs ,
const char * fname , int fd , const char * attr_name ,
2004-11-05 14:31:35 +03:00
void * p , ndr_push_flags_fn_t push_fn )
2004-11-05 10:29:02 +03:00
{
2005-01-06 05:32:43 +03:00
TALLOC_CTX * mem_ctx = talloc_new ( NULL ) ;
2004-11-05 10:29:02 +03:00
DATA_BLOB blob ;
NTSTATUS status ;
2004-11-05 14:31:35 +03:00
2005-01-21 09:56:13 +03:00
status = ndr_push_struct_blob ( & blob , mem_ctx , p , push_fn ) ;
2004-11-05 14:31:35 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( mem_ctx ) ;
return status ;
}
2004-11-13 08:47:27 +03:00
status = push_xattr_blob ( pvfs , attr_name , fname , fd , & blob ) ;
2004-11-05 14:31:35 +03:00
talloc_free ( mem_ctx ) ;
return status ;
}
/*
fill in file attributes from extended attributes
*/
NTSTATUS pvfs_dosattrib_load ( struct pvfs_state * pvfs , struct pvfs_filename * name , int fd )
{
NTSTATUS status ;
2004-11-05 10:29:02 +03:00
struct xattr_DosAttrib attrib ;
2005-01-06 05:32:43 +03:00
TALLOC_CTX * mem_ctx = talloc_new ( name ) ;
2004-11-05 10:29:02 +03:00
struct xattr_DosInfo1 * info1 ;
2004-11-24 09:09:14 +03:00
struct xattr_DosInfo2 * info2 ;
2004-11-05 10:29:02 +03:00
2004-11-17 08:58:04 +03:00
if ( name - > stream_name ! = NULL ) {
name - > stream_exists = False ;
} else {
name - > stream_exists = True ;
}
2004-11-05 14:31:35 +03:00
if ( ! ( pvfs - > flags & PVFS_FLAG_XATTR_ENABLE ) ) {
return NT_STATUS_OK ;
}
2004-11-13 08:47:27 +03:00
status = pvfs_xattr_ndr_load ( pvfs , mem_ctx , name - > full_name ,
fd , XATTR_DOSATTRIB_NAME ,
& attrib ,
( ndr_pull_flags_fn_t ) ndr_pull_xattr_DosAttrib ) ;
2004-11-05 10:29:02 +03:00
/* not having a DosAttrib is not an error */
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
talloc_free ( mem_ctx ) ;
2004-12-17 06:39:29 +03:00
return pvfs_stream_info ( pvfs , name , fd ) ;
2004-11-05 10:29:02 +03:00
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( mem_ctx ) ;
return status ;
}
switch ( attrib . version ) {
case 1 :
info1 = & attrib . info . info1 ;
2005-06-07 16:15:10 +04:00
name - > dos . attrib = pvfs_attrib_normalise ( info1 - > attrib ,
name - > st . st_mode ) ;
2004-11-05 10:29:02 +03:00
name - > dos . ea_size = info1 - > ea_size ;
if ( name - > st . st_size = = info1 - > size ) {
2004-11-17 10:17:55 +03:00
name - > dos . alloc_size =
pvfs_round_alloc_size ( pvfs , info1 - > alloc_size ) ;
2004-11-05 10:29:02 +03:00
}
2005-03-06 01:50:13 +03:00
if ( ! null_nttime ( info1 - > create_time ) ) {
2004-11-05 10:29:02 +03:00
name - > dos . create_time = info1 - > create_time ;
}
2005-03-06 01:50:13 +03:00
if ( ! null_nttime ( info1 - > change_time ) ) {
2004-11-05 10:29:02 +03:00
name - > dos . change_time = info1 - > change_time ;
}
2004-11-24 09:09:14 +03:00
name - > dos . flags = 0 ;
break ;
case 2 :
info2 = & attrib . info . info2 ;
2005-06-07 16:15:10 +04:00
name - > dos . attrib = pvfs_attrib_normalise ( info2 - > attrib ,
name - > st . st_mode ) ;
2004-11-24 09:09:14 +03:00
name - > dos . ea_size = info2 - > ea_size ;
if ( name - > st . st_size = = info2 - > size ) {
name - > dos . alloc_size =
pvfs_round_alloc_size ( pvfs , info2 - > alloc_size ) ;
}
2005-03-06 01:50:13 +03:00
if ( ! null_nttime ( info2 - > create_time ) ) {
2004-11-24 09:09:14 +03:00
name - > dos . create_time = info2 - > create_time ;
}
2005-03-06 01:50:13 +03:00
if ( ! null_nttime ( info2 - > change_time ) ) {
2004-11-24 09:09:14 +03:00
name - > dos . change_time = info2 - > change_time ;
}
name - > dos . flags = info2 - > flags ;
if ( name - > dos . flags & XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME ) {
name - > dos . write_time = info2 - > write_time ;
}
2004-11-05 10:29:02 +03:00
break ;
default :
DEBUG ( 0 , ( " ERROR: Unsupported xattr DosAttrib version %d on '%s' \n " ,
attrib . version , name - > full_name ) ) ;
talloc_free ( mem_ctx ) ;
return NT_STATUS_INVALID_LEVEL ;
}
talloc_free ( mem_ctx ) ;
2004-11-17 08:58:04 +03:00
status = pvfs_stream_info ( pvfs , name , fd ) ;
return status ;
2004-11-05 10:29:02 +03:00
}
/*
2004-11-05 14:31:35 +03:00
save the file attribute into the xattr
2004-11-05 10:29:02 +03:00
*/
2004-11-05 14:31:35 +03:00
NTSTATUS pvfs_dosattrib_save ( struct pvfs_state * pvfs , struct pvfs_filename * name , int fd )
2004-11-05 10:29:02 +03:00
{
struct xattr_DosAttrib attrib ;
2004-11-24 09:09:14 +03:00
struct xattr_DosInfo2 * info2 ;
2004-11-05 14:31:35 +03:00
if ( ! ( pvfs - > flags & PVFS_FLAG_XATTR_ENABLE ) ) {
return NT_STATUS_OK ;
}
2004-11-05 10:29:02 +03:00
2004-11-24 09:09:14 +03:00
attrib . version = 2 ;
info2 = & attrib . info . info2 ;
2004-11-05 10:29:02 +03:00
2005-06-07 16:15:10 +04:00
name - > dos . attrib = pvfs_attrib_normalise ( name - > dos . attrib , name - > st . st_mode ) ;
2004-11-06 12:34:17 +03:00
2004-11-24 09:09:14 +03:00
info2 - > attrib = name - > dos . attrib ;
info2 - > ea_size = name - > dos . ea_size ;
info2 - > size = name - > st . st_size ;
info2 - > alloc_size = name - > dos . alloc_size ;
info2 - > create_time = name - > dos . create_time ;
info2 - > change_time = name - > dos . change_time ;
info2 - > write_time = name - > dos . write_time ;
info2 - > flags = name - > dos . flags ;
info2 - > name = " " ;
2004-11-05 10:29:02 +03:00
2004-11-13 08:47:27 +03:00
return pvfs_xattr_ndr_save ( pvfs , name - > full_name , fd ,
XATTR_DOSATTRIB_NAME , & attrib ,
2004-11-05 14:31:35 +03:00
( ndr_push_flags_fn_t ) ndr_push_xattr_DosAttrib ) ;
}
2004-11-05 10:29:02 +03:00
2004-11-05 14:31:35 +03:00
/*
load the set of DOS EAs
*/
NTSTATUS pvfs_doseas_load ( struct pvfs_state * pvfs , struct pvfs_filename * name , int fd ,
struct xattr_DosEAs * eas )
{
NTSTATUS status ;
ZERO_STRUCTP ( eas ) ;
if ( ! ( pvfs - > flags & PVFS_FLAG_XATTR_ENABLE ) ) {
return NT_STATUS_OK ;
}
2004-11-13 08:47:27 +03:00
status = pvfs_xattr_ndr_load ( pvfs , eas , name - > full_name , fd , XATTR_DOSEAS_NAME ,
2004-11-05 14:31:35 +03:00
eas , ( ndr_pull_flags_fn_t ) ndr_pull_xattr_DosEAs ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
return NT_STATUS_OK ;
}
2004-11-05 10:29:02 +03:00
return status ;
}
2004-11-05 14:31:35 +03:00
/*
save the set of DOS EAs
*/
NTSTATUS pvfs_doseas_save ( struct pvfs_state * pvfs , struct pvfs_filename * name , int fd ,
struct xattr_DosEAs * eas )
{
if ( ! ( pvfs - > flags & PVFS_FLAG_XATTR_ENABLE ) ) {
return NT_STATUS_OK ;
}
2004-11-13 08:47:27 +03:00
return pvfs_xattr_ndr_save ( pvfs , name - > full_name , fd , XATTR_DOSEAS_NAME , eas ,
2004-11-05 14:31:35 +03:00
( ndr_push_flags_fn_t ) ndr_push_xattr_DosEAs ) ;
}
2004-11-15 09:57:26 +03:00
/*
load the set of streams from extended attributes
*/
NTSTATUS pvfs_streams_load ( struct pvfs_state * pvfs , struct pvfs_filename * name , int fd ,
struct xattr_DosStreams * streams )
{
NTSTATUS status ;
ZERO_STRUCTP ( streams ) ;
if ( ! ( pvfs - > flags & PVFS_FLAG_XATTR_ENABLE ) ) {
return NT_STATUS_OK ;
}
status = pvfs_xattr_ndr_load ( pvfs , streams , name - > full_name , fd ,
XATTR_DOSSTREAMS_NAME ,
streams ,
( ndr_pull_flags_fn_t ) ndr_pull_xattr_DosStreams ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
return NT_STATUS_OK ;
}
return status ;
}
/*
save the set of streams into filesystem xattr
*/
NTSTATUS pvfs_streams_save ( struct pvfs_state * pvfs , struct pvfs_filename * name , int fd ,
struct xattr_DosStreams * streams )
{
if ( ! ( pvfs - > flags & PVFS_FLAG_XATTR_ENABLE ) ) {
return NT_STATUS_OK ;
}
return pvfs_xattr_ndr_save ( pvfs , name - > full_name , fd ,
XATTR_DOSSTREAMS_NAME ,
streams ,
( ndr_push_flags_fn_t ) ndr_push_xattr_DosStreams ) ;
}
2004-11-17 08:58:04 +03:00
2004-11-18 06:31:35 +03:00
/*
load the current ACL from extended attributes
*/
NTSTATUS pvfs_acl_load ( struct pvfs_state * pvfs , struct pvfs_filename * name , int fd ,
2004-11-18 06:41:50 +03:00
struct xattr_NTACL * acl )
2004-11-18 06:31:35 +03:00
{
NTSTATUS status ;
ZERO_STRUCTP ( acl ) ;
if ( ! ( pvfs - > flags & PVFS_FLAG_XATTR_ENABLE ) ) {
2004-12-19 02:31:17 +03:00
return NT_STATUS_NOT_FOUND ;
2004-11-18 06:31:35 +03:00
}
status = pvfs_xattr_ndr_load ( pvfs , acl , name - > full_name , fd ,
2004-11-18 06:45:06 +03:00
XATTR_NTACL_NAME ,
2004-11-18 06:31:35 +03:00
acl ,
2004-11-18 06:41:50 +03:00
( ndr_pull_flags_fn_t ) ndr_pull_xattr_NTACL ) ;
2004-11-18 06:31:35 +03:00
return status ;
}
/*
save the acl for a file into filesystem xattr
*/
NTSTATUS pvfs_acl_save ( struct pvfs_state * pvfs , struct pvfs_filename * name , int fd ,
2004-11-18 06:41:50 +03:00
struct xattr_NTACL * acl )
2004-11-18 06:31:35 +03:00
{
NTSTATUS status ;
void * privs ;
if ( ! ( pvfs - > flags & PVFS_FLAG_XATTR_ENABLE ) ) {
return NT_STATUS_OK ;
}
/* this xattr is in the "system" namespace, so we need
admin privileges to set it */
privs = root_privileges ( ) ;
status = pvfs_xattr_ndr_save ( pvfs , name - > full_name , fd ,
2004-11-18 06:45:06 +03:00
XATTR_NTACL_NAME ,
2004-11-18 06:31:35 +03:00
acl ,
2004-11-18 06:41:50 +03:00
( ndr_push_flags_fn_t ) ndr_push_xattr_NTACL ) ;
2004-11-18 06:31:35 +03:00
talloc_free ( privs ) ;
return status ;
}
2004-11-17 08:58:04 +03:00
/*
create a zero length xattr with the given name
*/
NTSTATUS pvfs_xattr_create ( struct pvfs_state * pvfs ,
const char * fname , int fd ,
const char * attr_prefix ,
const char * attr_name )
{
NTSTATUS status ;
DATA_BLOB blob = data_blob ( NULL , 0 ) ;
char * aname = talloc_asprintf ( NULL , " %s%s " , attr_prefix , attr_name ) ;
if ( aname = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
status = push_xattr_blob ( pvfs , aname , fname , fd , & blob ) ;
talloc_free ( aname ) ;
return status ;
}
/*
delete a xattr with the given name
*/
NTSTATUS pvfs_xattr_delete ( struct pvfs_state * pvfs ,
const char * fname , int fd ,
const char * attr_prefix ,
const char * attr_name )
{
NTSTATUS status ;
char * aname = talloc_asprintf ( NULL , " %s%s " , attr_prefix , attr_name ) ;
if ( aname = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
status = delete_xattr ( pvfs , aname , fname , fd ) ;
talloc_free ( aname ) ;
return status ;
}
/*
load a xattr with the given name
*/
NTSTATUS pvfs_xattr_load ( struct pvfs_state * pvfs ,
TALLOC_CTX * mem_ctx ,
const char * fname , int fd ,
const char * attr_prefix ,
const char * attr_name ,
size_t estimated_size ,
DATA_BLOB * blob )
{
NTSTATUS status ;
char * aname = talloc_asprintf ( mem_ctx , " %s%s " , attr_prefix , attr_name ) ;
if ( aname = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
status = pull_xattr_blob ( pvfs , mem_ctx , aname , fname , fd , estimated_size , blob ) ;
talloc_free ( aname ) ;
return status ;
}
/*
save a xattr with the given name
*/
NTSTATUS pvfs_xattr_save ( struct pvfs_state * pvfs ,
const char * fname , int fd ,
const char * attr_prefix ,
const char * attr_name ,
const DATA_BLOB * blob )
{
NTSTATUS status ;
char * aname = talloc_asprintf ( NULL , " %s%s " , attr_prefix , attr_name ) ;
if ( aname = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
status = push_xattr_blob ( pvfs , aname , fname , fd , blob ) ;
talloc_free ( aname ) ;
return status ;
}
2004-12-17 06:39:29 +03:00
2005-06-14 05:11:24 +04:00
/*
probe for system support for xattrs
*/
void pvfs_xattr_probe ( struct pvfs_state * pvfs )
{
TALLOC_CTX * tmp_ctx = talloc_new ( pvfs ) ;
DATA_BLOB blob ;
pull_xattr_blob ( pvfs , tmp_ctx , " user.XattrProbe " , pvfs - > base_directory ,
- 1 , 1 , & blob ) ;
pull_xattr_blob ( pvfs , tmp_ctx , " security.XattrProbe " , pvfs - > base_directory ,
- 1 , 1 , & blob ) ;
talloc_free ( tmp_ctx ) ;
}