2004-06-28 10:46:27 +04:00
/*
Unix SMB / CIFS implementation .
simple kerberos5 / SPNEGO routines
Copyright ( C ) Andrew Tridgell 2001
Copyright ( C ) Jim McDonough < jmcd @ us . ibm . com > 2002
Copyright ( C ) Andrew Bartlett 2002 - 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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2004-06-28 10:46:27 +04:00
( 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
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2004-06-28 10:46:27 +04:00
*/
# include "includes.h"
2009-04-16 04:17:57 +04:00
# include "libcli/auth/msrpc_parse.h"
2004-06-28 10:46:27 +04:00
/*
this is a tiny msrpc packet generator . I am only using this to
2023-04-27 16:53:25 +03:00
avoid tying this code to a particular variant of our rpc code . This
2004-06-28 10:46:27 +04:00
generator is not general enough for all our rpc needs , its just
enough for the spnego / ntlmssp code
format specifiers are :
U = unicode string ( input is unix string )
a = address ( input is char * unix_string )
( 1 byte type , 1 byte length , unicode / ASCII string , all inline )
A = ASCII string ( input is unix string )
B = data blob ( pointer + length )
b = data blob in header ( pointer + length )
D
d = word ( 4 bytes )
C = constant ascii string
*/
2011-03-29 00:26:27 +04:00
NTSTATUS msrpc_gen ( TALLOC_CTX * mem_ctx ,
2008-01-04 02:22:04 +03:00
DATA_BLOB * blob ,
2004-06-28 10:46:27 +04:00
const char * format , . . . )
{
2009-03-02 00:24:34 +03:00
int i , j ;
bool ret ;
2004-06-28 10:46:27 +04:00
va_list ap ;
char * s ;
uint8_t * b ;
int head_size = 0 , data_size = 0 ;
int head_ofs , data_ofs ;
2004-09-23 01:45:52 +04:00
int * intargs ;
2009-03-02 00:24:34 +03:00
size_t n ;
2004-09-23 01:45:52 +04:00
DATA_BLOB * pointers ;
2005-01-27 10:08:20 +03:00
pointers = talloc_array ( mem_ctx , DATA_BLOB , strlen ( format ) ) ;
2011-03-29 00:26:27 +04:00
if ( ! pointers ) {
return NT_STATUS_NO_MEMORY ;
}
2005-01-27 10:08:20 +03:00
intargs = talloc_array ( pointers , int , strlen ( format ) ) ;
2011-03-29 00:26:27 +04:00
if ( ! intargs ) {
return NT_STATUS_NO_MEMORY ;
}
2004-06-28 10:46:27 +04:00
/* first scan the format to work out the header and body size */
va_start ( ap , format ) ;
for ( i = 0 ; format [ i ] ; i + + ) {
switch ( format [ i ] ) {
case ' U ' :
s = va_arg ( ap , char * ) ;
head_size + = 8 ;
2009-04-23 16:24:16 +04:00
ret = push_ucs2_talloc (
pointers ,
( smb_ucs2_t * * ) ( void * ) & pointers [ i ] . data ,
s , & n ) ;
2009-03-02 00:24:34 +03:00
if ( ! ret ) {
2009-06-12 15:01:41 +04:00
va_end ( ap ) ;
2011-06-20 08:55:32 +04:00
return map_nt_error_from_unix_common ( errno ) ;
2004-09-23 01:45:52 +04:00
}
pointers [ i ] . length = n ;
pointers [ i ] . length - = 2 ;
data_size + = pointers [ i ] . length ;
2004-06-28 10:46:27 +04:00
break ;
case ' A ' :
s = va_arg ( ap , char * ) ;
head_size + = 8 ;
2009-04-23 16:24:16 +04:00
ret = push_ascii_talloc (
pointers , ( char * * ) ( void * ) & pointers [ i ] . data ,
s , & n ) ;
2009-03-02 00:24:34 +03:00
if ( ! ret ) {
2009-06-12 15:01:41 +04:00
va_end ( ap ) ;
2011-06-20 08:55:32 +04:00
return map_nt_error_from_unix_common ( errno ) ;
2004-09-23 01:45:52 +04:00
}
pointers [ i ] . length = n ;
pointers [ i ] . length - = 1 ;
data_size + = pointers [ i ] . length ;
2004-06-28 10:46:27 +04:00
break ;
case ' a ' :
2009-03-02 00:24:34 +03:00
j = va_arg ( ap , int ) ;
intargs [ i ] = j ;
2004-06-28 10:46:27 +04:00
s = va_arg ( ap , char * ) ;
2009-04-23 16:24:16 +04:00
ret = push_ucs2_talloc (
pointers ,
( smb_ucs2_t * * ) ( void * ) & pointers [ i ] . data ,
s , & n ) ;
2009-03-02 00:24:34 +03:00
if ( ! ret ) {
2009-06-12 15:01:41 +04:00
va_end ( ap ) ;
2011-06-20 08:55:32 +04:00
return map_nt_error_from_unix_common ( errno ) ;
2004-09-23 01:45:52 +04:00
}
pointers [ i ] . length = n ;
pointers [ i ] . length - = 2 ;
data_size + = pointers [ i ] . length + 4 ;
2004-06-28 10:46:27 +04:00
break ;
case ' B ' :
b = va_arg ( ap , uint8_t * ) ;
head_size + = 8 ;
2004-09-23 01:45:52 +04:00
pointers [ i ] . data = b ;
pointers [ i ] . length = va_arg ( ap , int ) ;
data_size + = pointers [ i ] . length ;
2004-06-28 10:46:27 +04:00
break ;
case ' b ' :
b = va_arg ( ap , uint8_t * ) ;
2004-09-23 01:45:52 +04:00
pointers [ i ] . data = b ;
pointers [ i ] . length = va_arg ( ap , int ) ;
head_size + = pointers [ i ] . length ;
2004-06-28 10:46:27 +04:00
break ;
case ' d ' :
2009-03-02 00:24:34 +03:00
j = va_arg ( ap , int ) ;
intargs [ i ] = j ;
2004-06-28 10:46:27 +04:00
head_size + = 4 ;
break ;
case ' C ' :
s = va_arg ( ap , char * ) ;
2004-11-29 15:01:46 +03:00
pointers [ i ] . data = ( uint8_t * ) s ;
2004-09-23 01:45:52 +04:00
pointers [ i ] . length = strlen ( s ) + 1 ;
head_size + = pointers [ i ] . length ;
2004-06-28 10:46:27 +04:00
break ;
2011-03-29 00:26:27 +04:00
default :
va_end ( ap ) ;
return NT_STATUS_INVALID_PARAMETER ;
2004-06-28 10:46:27 +04:00
}
}
va_end ( ap ) ;
2011-03-29 00:26:27 +04:00
if ( head_size + data_size = = 0 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2004-06-28 10:46:27 +04:00
/* allocate the space, then scan the format again to fill in the values */
* blob = data_blob_talloc ( mem_ctx , NULL , head_size + data_size ) ;
2011-03-29 00:26:27 +04:00
if ( ! blob - > data ) {
return NT_STATUS_NO_MEMORY ;
}
2004-06-28 10:46:27 +04:00
head_ofs = 0 ;
data_ofs = head_size ;
va_start ( ap , format ) ;
for ( i = 0 ; format [ i ] ; i + + ) {
switch ( format [ i ] ) {
case ' U ' :
case ' A ' :
2004-09-23 01:45:52 +04:00
case ' B ' :
n = pointers [ i ] . length ;
2004-06-28 10:46:27 +04:00
SSVAL ( blob - > data , head_ofs , n ) ; head_ofs + = 2 ;
SSVAL ( blob - > data , head_ofs , n ) ; head_ofs + = 2 ;
SIVAL ( blob - > data , head_ofs , data_ofs ) ; head_ofs + = 4 ;
2004-09-23 01:45:52 +04:00
if ( pointers [ i ] . data & & n ) /* don't follow null pointers... */
memcpy ( blob - > data + data_ofs , pointers [ i ] . data , n ) ;
2004-06-28 10:46:27 +04:00
data_ofs + = n ;
break ;
case ' a ' :
2009-03-02 00:24:34 +03:00
j = intargs [ i ] ;
SSVAL ( blob - > data , data_ofs , j ) ; data_ofs + = 2 ;
2004-06-28 10:46:27 +04:00
2004-09-23 01:45:52 +04:00
n = pointers [ i ] . length ;
SSVAL ( blob - > data , data_ofs , n ) ; data_ofs + = 2 ;
2012-02-26 00:17:40 +04:00
memcpy ( blob - > data + data_ofs , pointers [ i ] . data , n ) ;
2004-06-28 10:46:27 +04:00
data_ofs + = n ;
break ;
case ' d ' :
2009-03-02 00:24:34 +03:00
j = intargs [ i ] ;
SIVAL ( blob - > data , head_ofs , j ) ;
2004-09-23 01:45:52 +04:00
head_ofs + = 4 ;
2004-06-28 10:46:27 +04:00
break ;
case ' b ' :
2004-09-23 01:45:52 +04:00
n = pointers [ i ] . length ;
2010-05-19 21:34:44 +04:00
if ( pointers [ i ] . data & & n ) {
/* don't follow null pointers... */
memcpy ( blob - > data + head_ofs , pointers [ i ] . data , n ) ;
}
2004-06-28 10:46:27 +04:00
head_ofs + = n ;
break ;
case ' C ' :
2004-09-23 01:45:52 +04:00
n = pointers [ i ] . length ;
memcpy ( blob - > data + head_ofs , pointers [ i ] . data , n ) ;
head_ofs + = n ;
2004-06-28 10:46:27 +04:00
break ;
2011-03-29 00:26:27 +04:00
default :
va_end ( ap ) ;
return NT_STATUS_INVALID_PARAMETER ;
2004-06-28 10:46:27 +04:00
}
}
va_end ( ap ) ;
2004-09-23 01:45:52 +04:00
talloc_free ( pointers ) ;
2004-06-28 10:46:27 +04:00
2011-03-29 00:26:27 +04:00
return NT_STATUS_OK ;
2004-06-28 10:46:27 +04:00
}
/* a helpful macro to avoid running over the end of our blob */
# define NEED_DATA(amount) \
if ( ( head_ofs + amount ) > blob - > length ) { \
2009-06-12 15:01:41 +04:00
va_end ( ap ) ; \
2007-10-07 02:16:19 +04:00
return false ; \
2004-06-28 10:46:27 +04:00
}
2008-11-01 22:58:41 +03:00
/**
2024-09-13 05:22:30 +03:00
this is a tiny msrpc packet parser . This is the partner of msrpc_gen
2004-06-28 10:46:27 +04:00
format specifiers are :
U = unicode string ( output is unix string )
A = ascii string
B = data blob
b = data blob in header
d = word ( 4 bytes )
C = constant ascii string
*/
2008-01-04 02:22:04 +03:00
bool msrpc_parse ( TALLOC_CTX * mem_ctx ,
const DATA_BLOB * blob ,
2004-06-28 10:46:27 +04:00
const char * format , . . . )
{
int i ;
va_list ap ;
2009-03-16 13:17:29 +03:00
char * * ps , * s ;
2004-06-28 10:46:27 +04:00
DATA_BLOB * b ;
size_t head_ofs = 0 ;
uint16_t len1 , len2 ;
uint32_t ptr ;
uint32_t * v ;
2007-12-12 21:38:22 +03:00
bool ret = true ;
2004-06-28 10:46:27 +04:00
va_start ( ap , format ) ;
for ( i = 0 ; format [ i ] ; i + + ) {
switch ( format [ i ] ) {
case ' U ' :
NEED_DATA ( 8 ) ;
len1 = SVAL ( blob - > data , head_ofs ) ; head_ofs + = 2 ;
len2 = SVAL ( blob - > data , head_ofs ) ; head_ofs + = 2 ;
ptr = IVAL ( blob - > data , head_ofs ) ; head_ofs + = 4 ;
2009-03-16 13:17:29 +03:00
ps = va_arg ( ap , char * * ) ;
2004-06-28 10:46:27 +04:00
if ( len1 = = 0 & & len2 = = 0 ) {
2016-05-09 17:14:31 +03:00
* ps = talloc_strdup ( mem_ctx , " " ) ;
if ( * ps = = NULL ) {
ret = false ;
goto cleanup ;
}
2004-06-28 10:46:27 +04:00
} else {
2023-10-06 02:36:13 +03:00
size_t pull_len ;
2004-06-28 10:46:27 +04:00
/* make sure its in the right format - be strict */
if ( ( len1 ! = len2 ) | | ( ptr + len1 < ptr ) | | ( ptr + len1 < len1 ) | | ( ptr + len1 > blob - > length ) ) {
2007-12-12 21:38:22 +03:00
ret = false ;
goto cleanup ;
2004-06-28 10:46:27 +04:00
}
if ( len1 & 1 ) {
/* if odd length and unicode */
2007-12-12 21:38:22 +03:00
ret = false ;
goto cleanup ;
}
2008-06-27 14:42:07 +04:00
if ( blob - > data + ptr < ( uint8_t * ) ( uintptr_t ) ptr | |
2007-12-12 21:38:22 +03:00
blob - > data + ptr < blob - > data ) {
ret = false ;
goto cleanup ;
2004-06-28 10:46:27 +04:00
}
2023-10-06 02:36:13 +03:00
if ( ! convert_string_talloc ( mem_ctx , CH_UTF16 , CH_UNIX ,
blob - > data + ptr , len1 ,
ps , & pull_len ) ) {
ret = false ;
goto cleanup ;
2004-06-28 10:46:27 +04:00
}
}
break ;
case ' A ' :
NEED_DATA ( 8 ) ;
len1 = SVAL ( blob - > data , head_ofs ) ; head_ofs + = 2 ;
len2 = SVAL ( blob - > data , head_ofs ) ; head_ofs + = 2 ;
ptr = IVAL ( blob - > data , head_ofs ) ; head_ofs + = 4 ;
2009-03-16 13:17:29 +03:00
ps = ( char * * ) va_arg ( ap , char * * ) ;
2004-06-28 10:46:27 +04:00
/* make sure its in the right format - be strict */
if ( len1 = = 0 & & len2 = = 0 ) {
2016-05-09 17:14:31 +03:00
* ps = talloc_strdup ( mem_ctx , " " ) ;
if ( * ps = = NULL ) {
ret = false ;
goto cleanup ;
}
2004-06-28 10:46:27 +04:00
} else {
if ( ( len1 ! = len2 ) | | ( ptr + len1 < ptr ) | | ( ptr + len1 < len1 ) | | ( ptr + len1 > blob - > length ) ) {
2007-12-12 21:38:22 +03:00
ret = false ;
goto cleanup ;
2004-06-28 10:46:27 +04:00
}
2008-06-27 14:42:07 +04:00
if ( blob - > data + ptr < ( uint8_t * ) ( uintptr_t ) ptr | |
2007-12-12 21:38:22 +03:00
blob - > data + ptr < blob - > data ) {
ret = false ;
goto cleanup ;
}
2004-06-28 10:46:27 +04:00
if ( 0 < len1 ) {
2009-03-16 13:17:29 +03:00
size_t pull_len ;
if ( ! convert_string_talloc ( mem_ctx , CH_DOS , CH_UNIX ,
blob - > data + ptr , len1 ,
2011-03-24 02:59:41 +03:00
ps , & pull_len ) ) {
2007-12-12 21:38:22 +03:00
ret = false ;
goto cleanup ;
2004-06-28 10:46:27 +04:00
}
} else {
2016-05-09 17:14:31 +03:00
* ps = talloc_strdup ( mem_ctx , " " ) ;
if ( * ps = = NULL ) {
ret = false ;
goto cleanup ;
}
2004-06-28 10:46:27 +04:00
}
}
break ;
case ' B ' :
NEED_DATA ( 8 ) ;
len1 = SVAL ( blob - > data , head_ofs ) ; head_ofs + = 2 ;
len2 = SVAL ( blob - > data , head_ofs ) ; head_ofs + = 2 ;
ptr = IVAL ( blob - > data , head_ofs ) ; head_ofs + = 4 ;
b = ( DATA_BLOB * ) va_arg ( ap , void * ) ;
if ( len1 = = 0 & & len2 = = 0 ) {
* b = data_blob_talloc ( mem_ctx , NULL , 0 ) ;
} else {
/* make sure its in the right format - be strict */
if ( ( len1 ! = len2 ) | | ( ptr + len1 < ptr ) | | ( ptr + len1 < len1 ) | | ( ptr + len1 > blob - > length ) ) {
2007-12-12 21:38:22 +03:00
ret = false ;
goto cleanup ;
}
2008-06-27 14:42:07 +04:00
if ( blob - > data + ptr < ( uint8_t * ) ( uintptr_t ) ptr | |
2007-12-12 21:38:22 +03:00
blob - > data + ptr < blob - > data ) {
ret = false ;
goto cleanup ;
2004-06-28 10:46:27 +04:00
}
* b = data_blob_talloc ( mem_ctx , blob - > data + ptr , len1 ) ;
}
break ;
case ' b ' :
b = ( DATA_BLOB * ) va_arg ( ap , void * ) ;
2010-01-05 20:41:24 +03:00
len1 = va_arg ( ap , unsigned int ) ;
2004-06-28 10:46:27 +04:00
/* make sure its in the right format - be strict */
NEED_DATA ( len1 ) ;
2007-12-12 21:38:22 +03:00
if ( blob - > data + head_ofs < ( uint8_t * ) head_ofs | |
blob - > data + head_ofs < blob - > data ) {
ret = false ;
goto cleanup ;
}
2004-06-28 10:46:27 +04:00
* b = data_blob_talloc ( mem_ctx , blob - > data + head_ofs , len1 ) ;
head_ofs + = len1 ;
break ;
case ' d ' :
v = va_arg ( ap , uint32_t * ) ;
NEED_DATA ( 4 ) ;
* v = IVAL ( blob - > data , head_ofs ) ; head_ofs + = 4 ;
break ;
case ' C ' :
s = va_arg ( ap , char * ) ;
2007-12-12 21:38:22 +03:00
if ( blob - > data + head_ofs < ( uint8_t * ) head_ofs | |
2009-03-16 13:17:29 +03:00
blob - > data + head_ofs < blob - > data | |
( head_ofs + ( strlen ( s ) + 1 ) ) > blob - > length ) {
2007-12-12 21:38:22 +03:00
ret = false ;
goto cleanup ;
}
2009-03-16 13:17:29 +03:00
if ( memcmp ( blob - > data + head_ofs , s , strlen ( s ) + 1 ) ! = 0 ) {
2007-12-12 21:38:22 +03:00
ret = false ;
goto cleanup ;
2004-06-28 10:46:27 +04:00
}
2009-03-16 13:17:29 +03:00
head_ofs + = ( strlen ( s ) + 1 ) ;
2004-06-28 10:46:27 +04:00
break ;
}
}
2007-12-12 21:38:22 +03:00
cleanup :
va_end ( ap ) ;
return ret ;
2004-06-28 10:46:27 +04:00
}