2003-08-13 01:53:07 +00:00
/*
Unix SMB / CIFS implementation .
parsing of EA ( extended attribute ) lists
Copyright ( C ) Andrew Tridgell 2003
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"
/*
work out how many bytes on the wire a ea list will consume .
This assumes the names are strict ascii , which should be a
reasonable assumption
*/
uint_t ea_list_size ( uint_t num_eas , struct ea_struct * eas )
{
uint_t total = 4 ;
int i ;
for ( i = 0 ; i < num_eas ; i + + ) {
total + = 4 + strlen ( eas [ i ] . name . s ) + 1 + eas [ i ] . value . length ;
}
return total ;
}
2004-12-17 22:47:49 +00:00
/*
work out how many bytes on the wire a ea name list will consume .
*/
static uint_t ea_name_list_size ( uint_t num_names , struct ea_name * eas )
{
uint_t total = 4 ;
int i ;
for ( i = 0 ; i < num_names ; i + + ) {
total + = 1 + strlen ( eas [ i ] . name . s ) + 1 ;
}
return total ;
}
2004-11-17 22:00:15 +00:00
/*
work out how many bytes on the wire a chained ea list will consume .
This assumes the names are strict ascii , which should be a
reasonable assumption
*/
uint_t ea_list_size_chained ( uint_t num_eas , struct ea_struct * eas )
{
uint_t total = 0 ;
int i ;
for ( i = 0 ; i < num_eas ; i + + ) {
uint_t len = 8 + strlen ( eas [ i ] . name . s ) + 1 + eas [ i ] . value . length ;
len = ( len + 3 ) & ~ 3 ;
total + = len ;
}
return total ;
}
2003-08-13 01:53:07 +00:00
/*
put a ea_list into a pre - allocated buffer - buffer must be at least
of size ea_list_size ( )
*/
2004-11-22 08:31:36 +00:00
void ea_put_list ( uint8_t * data , uint_t num_eas , struct ea_struct * eas )
2003-08-13 01:53:07 +00:00
{
int i ;
2004-05-25 16:24:13 +00:00
uint32_t ea_size ;
2003-08-13 01:53:07 +00:00
ea_size = ea_list_size ( num_eas , eas ) ;
SIVAL ( data , 0 , ea_size ) ;
data + = 4 ;
for ( i = 0 ; i < num_eas ; i + + ) {
uint_t nlen = strlen ( eas [ i ] . name . s ) ;
SCVAL ( data , 0 , eas [ i ] . flags ) ;
SCVAL ( data , 1 , nlen ) ;
SSVAL ( data , 2 , eas [ i ] . value . length ) ;
memcpy ( data + 4 , eas [ i ] . name . s , nlen + 1 ) ;
memcpy ( data + 4 + nlen + 1 , eas [ i ] . value . data , eas [ i ] . value . length ) ;
data + = 4 + nlen + 1 + eas [ i ] . value . length ;
}
}
2004-11-17 22:00:15 +00:00
/*
put a chained ea_list into a pre - allocated buffer - buffer must be
at least of size ea_list_size ( )
*/
2004-11-22 08:31:36 +00:00
void ea_put_list_chained ( uint8_t * data , uint_t num_eas , struct ea_struct * eas )
2004-11-17 22:00:15 +00:00
{
int i ;
for ( i = 0 ; i < num_eas ; i + + ) {
uint_t nlen = strlen ( eas [ i ] . name . s ) ;
uint32_t len = 8 + nlen + 1 + eas [ i ] . value . length ;
uint_t pad = ( ( len + 3 ) & ~ 3 ) - len ;
if ( i = = num_eas - 1 ) {
SIVAL ( data , 0 , 0 ) ;
} else {
SIVAL ( data , 0 , len + pad ) ;
}
SCVAL ( data , 4 , eas [ i ] . flags ) ;
SCVAL ( data , 5 , nlen ) ;
SSVAL ( data , 6 , eas [ i ] . value . length ) ;
memcpy ( data + 8 , eas [ i ] . name . s , nlen + 1 ) ;
memcpy ( data + 8 + nlen + 1 , eas [ i ] . value . data , eas [ i ] . value . length ) ;
memset ( data + len , 0 , pad ) ;
data + = len + pad ;
}
}
2003-08-13 01:53:07 +00:00
/*
pull a ea_struct from a buffer . Return the number of bytes consumed
*/
uint_t ea_pull_struct ( const DATA_BLOB * blob ,
TALLOC_CTX * mem_ctx ,
struct ea_struct * ea )
{
2004-05-25 17:50:17 +00:00
uint8_t nlen ;
2004-05-25 17:24:24 +00:00
uint16_t vlen ;
2003-08-13 01:53:07 +00:00
if ( blob - > length < 6 ) {
return 0 ;
}
ea - > flags = CVAL ( blob - > data , 0 ) ;
nlen = CVAL ( blob - > data , 1 ) ;
vlen = SVAL ( blob - > data , 2 ) ;
if ( nlen + 1 + vlen > blob - > length - 4 ) {
return 0 ;
}
2004-11-25 20:01:47 +00:00
ea - > name . s = talloc_strndup ( mem_ctx , ( const char * ) ( blob - > data + 4 ) , nlen ) ;
2003-08-13 01:53:07 +00:00
ea - > name . private_length = nlen ;
ea - > value = data_blob_talloc ( mem_ctx , NULL , vlen + 1 ) ;
if ( ! ea - > value . data ) return 0 ;
if ( vlen ) {
memcpy ( ea - > value . data , blob - > data + 4 + nlen + 1 , vlen ) ;
}
ea - > value . data [ vlen ] = 0 ;
ea - > value . length - - ;
return 4 + nlen + 1 + vlen ;
}
/*
pull a ea_list from a buffer
*/
NTSTATUS ea_pull_list ( const DATA_BLOB * blob ,
2004-12-17 04:51:23 +00:00
TALLOC_CTX * mem_ctx ,
uint_t * num_eas , struct ea_struct * * eas )
2003-08-13 01:53:07 +00:00
{
int n ;
2004-05-25 16:24:13 +00:00
uint32_t ea_size , ofs ;
2003-08-13 01:53:07 +00:00
if ( blob - > length < 4 ) {
return NT_STATUS_INFO_LENGTH_MISMATCH ;
}
ea_size = IVAL ( blob - > data , 0 ) ;
if ( ea_size > blob - > length ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2004-11-17 22:00:15 +00:00
ofs = 4 ;
2003-08-13 01:53:07 +00:00
n = 0 ;
* num_eas = 0 ;
* eas = NULL ;
2004-11-17 22:00:15 +00:00
while ( ofs < ea_size ) {
2003-08-13 01:53:07 +00:00
uint_t len ;
DATA_BLOB blob2 ;
blob2 . data = blob - > data + ofs ;
blob2 . length = ea_size - ofs ;
2005-01-27 07:08:20 +00:00
* eas = talloc_realloc ( mem_ctx , * eas , struct ea_struct , n + 1 ) ;
2003-08-13 01:53:07 +00:00
if ( ! * eas ) return NT_STATUS_NO_MEMORY ;
len = ea_pull_struct ( & blob2 , mem_ctx , & ( * eas ) [ n ] ) ;
if ( len = = 0 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
ofs + = len ;
n + + ;
}
* num_eas = n ;
return NT_STATUS_OK ;
}
2004-11-17 22:00:15 +00:00
/*
pull a chained ea_list from a buffer
*/
NTSTATUS ea_pull_list_chained ( const DATA_BLOB * blob ,
TALLOC_CTX * mem_ctx ,
uint_t * num_eas , struct ea_struct * * eas )
{
int n ;
uint32_t ofs ;
if ( blob - > length < 4 ) {
return NT_STATUS_INFO_LENGTH_MISMATCH ;
}
ofs = 0 ;
n = 0 ;
* num_eas = 0 ;
* eas = NULL ;
while ( ofs < blob - > length ) {
uint_t len ;
DATA_BLOB blob2 ;
uint32_t next_ofs = IVAL ( blob - > data , ofs ) ;
blob2 . data = blob - > data + ofs + 4 ;
blob2 . length = blob - > length - ( ofs + 4 ) ;
2005-01-27 07:08:20 +00:00
* eas = talloc_realloc ( mem_ctx , * eas , struct ea_struct , n + 1 ) ;
2004-11-17 22:00:15 +00:00
if ( ! * eas ) return NT_STATUS_NO_MEMORY ;
len = ea_pull_struct ( & blob2 , mem_ctx , & ( * eas ) [ n ] ) ;
if ( len = = 0 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
ofs + = next_ofs ;
if ( ofs + 4 > blob - > length ) {
return NT_STATUS_INVALID_PARAMETER ;
}
n + + ;
if ( next_ofs = = 0 ) break ;
}
* num_eas = n ;
return NT_STATUS_OK ;
}
2004-12-17 22:47:49 +00:00
/*
pull a ea_name from a buffer . Return the number of bytes consumed
*/
static uint_t ea_pull_name ( const DATA_BLOB * blob ,
TALLOC_CTX * mem_ctx ,
struct ea_name * ea )
{
uint8_t nlen ;
if ( blob - > length < 2 ) {
return 0 ;
}
nlen = CVAL ( blob - > data , 0 ) ;
if ( nlen + 2 > blob - > length ) {
return 0 ;
}
ea - > name . s = talloc_strndup ( mem_ctx , ( const char * ) ( blob - > data + 1 ) , nlen ) ;
ea - > name . private_length = nlen ;
return nlen + 2 ;
}
/*
pull a ea_name list from a buffer
*/
NTSTATUS ea_pull_name_list ( const DATA_BLOB * blob ,
TALLOC_CTX * mem_ctx ,
uint_t * num_names , struct ea_name * * ea_names )
{
int n ;
uint32_t ea_size , ofs ;
if ( blob - > length < 4 ) {
return NT_STATUS_INFO_LENGTH_MISMATCH ;
}
ea_size = IVAL ( blob - > data , 0 ) ;
if ( ea_size > blob - > length ) {
return NT_STATUS_INVALID_PARAMETER ;
}
ofs = 4 ;
n = 0 ;
* num_names = 0 ;
* ea_names = NULL ;
while ( ofs < ea_size ) {
uint_t len ;
DATA_BLOB blob2 ;
blob2 . data = blob - > data + ofs ;
blob2 . length = ea_size - ofs ;
2005-01-27 07:08:20 +00:00
* ea_names = talloc_realloc ( mem_ctx , * ea_names , struct ea_name , n + 1 ) ;
2004-12-17 22:47:49 +00:00
if ( ! * ea_names ) return NT_STATUS_NO_MEMORY ;
len = ea_pull_name ( & blob2 , mem_ctx , & ( * ea_names ) [ n ] ) ;
if ( len = = 0 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
ofs + = len ;
n + + ;
}
* num_names = n ;
return NT_STATUS_OK ;
}
/*
put a ea_name list into a data blob
*/
BOOL ea_push_name_list ( TALLOC_CTX * mem_ctx ,
DATA_BLOB * data , uint_t num_names , struct ea_name * eas )
{
int i ;
uint32_t ea_size ;
uint32_t off ;
ea_size = ea_name_list_size ( num_names , eas ) ;
* data = data_blob_talloc ( mem_ctx , NULL , ea_size ) ;
if ( data - > data = = NULL ) {
return False ;
}
SIVAL ( data - > data , 0 , ea_size ) ;
off = 4 ;
2004-11-17 22:00:15 +00:00
2004-12-17 22:47:49 +00:00
for ( i = 0 ; i < num_names ; i + + ) {
uint_t nlen = strlen ( eas [ i ] . name . s ) ;
SCVAL ( data - > data , off , nlen ) ;
memcpy ( data - > data + off + 1 , eas [ i ] . name . s , nlen + 1 ) ;
off + = 1 + nlen + 1 ;
}
return True ;
}