2001-10-12 08:49:42 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2001-10-12 08:49:42 +04:00
simple kerberos5 / SPNEGO routines
Copyright ( C ) Andrew Tridgell 2001
2002-08-17 21:00:51 +04:00
Copyright ( C ) Jim McDonough 2002
2001-10-12 08:49:42 +04:00
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"
/*
generate a negTokenInit packet given a GUID , a list of supported
2001-10-22 00:51:27 +04:00
OIDs ( the mechanisms ) and a principal name string
2001-10-12 08:49:42 +04:00
*/
2001-10-17 12:54:19 +04:00
DATA_BLOB spnego_gen_negTokenInit ( uint8 guid [ 16 ] ,
2001-10-12 08:49:42 +04:00
const char * OIDs [ ] ,
2001-10-22 00:51:27 +04:00
const char * principal )
2001-10-12 08:49:42 +04:00
{
int i ;
ASN1_DATA data ;
2001-10-17 12:54:19 +04:00
DATA_BLOB ret ;
2001-10-12 08:49:42 +04:00
memset ( & data , 0 , sizeof ( data ) ) ;
asn1_write ( & data , guid , 16 ) ;
asn1_push_tag ( & data , ASN1_APPLICATION ( 0 ) ) ;
asn1_write_OID ( & data , OID_SPNEGO ) ;
asn1_push_tag ( & data , ASN1_CONTEXT ( 0 ) ) ;
asn1_push_tag ( & data , ASN1_SEQUENCE ( 0 ) ) ;
asn1_push_tag ( & data , ASN1_CONTEXT ( 0 ) ) ;
asn1_push_tag ( & data , ASN1_SEQUENCE ( 0 ) ) ;
for ( i = 0 ; OIDs [ i ] ; i + + ) {
asn1_write_OID ( & data , OIDs [ i ] ) ;
}
asn1_pop_tag ( & data ) ;
asn1_pop_tag ( & data ) ;
asn1_push_tag ( & data , ASN1_CONTEXT ( 3 ) ) ;
asn1_push_tag ( & data , ASN1_SEQUENCE ( 0 ) ) ;
asn1_push_tag ( & data , ASN1_CONTEXT ( 0 ) ) ;
2001-10-22 00:51:27 +04:00
asn1_write_GeneralString ( & data , principal ) ;
2001-10-12 08:49:42 +04:00
asn1_pop_tag ( & data ) ;
asn1_pop_tag ( & data ) ;
asn1_pop_tag ( & data ) ;
asn1_pop_tag ( & data ) ;
asn1_pop_tag ( & data ) ;
asn1_pop_tag ( & data ) ;
if ( data . has_error ) {
DEBUG ( 1 , ( " Failed to build negTokenInit at offset %d \n " , ( int ) data . ofs ) ) ;
asn1_free ( & data ) ;
}
2001-10-17 12:54:19 +04:00
ret = data_blob ( data . data , data . length ) ;
asn1_free ( & data ) ;
return ret ;
2001-10-12 08:49:42 +04:00
}
/*
parse a negTokenInit packet giving a GUID , a list of supported
2001-10-22 00:51:27 +04:00
OIDs ( the mechanisms ) and a principal name string
2001-10-12 08:49:42 +04:00
*/
BOOL spnego_parse_negTokenInit ( DATA_BLOB blob ,
uint8 guid [ 16 ] ,
char * OIDs [ ASN1_MAX_OIDS ] ,
2001-10-22 00:51:27 +04:00
char * * principal )
2001-10-12 08:49:42 +04:00
{
int i ;
BOOL ret ;
ASN1_DATA data ;
asn1_load ( & data , blob ) ;
asn1_read ( & data , guid , 16 ) ;
asn1_start_tag ( & data , ASN1_APPLICATION ( 0 ) ) ;
asn1_check_OID ( & data , OID_SPNEGO ) ;
asn1_start_tag ( & data , ASN1_CONTEXT ( 0 ) ) ;
asn1_start_tag ( & data , ASN1_SEQUENCE ( 0 ) ) ;
asn1_start_tag ( & data , ASN1_CONTEXT ( 0 ) ) ;
asn1_start_tag ( & data , ASN1_SEQUENCE ( 0 ) ) ;
for ( i = 0 ; asn1_tag_remaining ( & data ) > 0 & & i < ASN1_MAX_OIDS ; i + + ) {
char * oid = NULL ;
asn1_read_OID ( & data , & oid ) ;
OIDs [ i ] = oid ;
}
OIDs [ i ] = NULL ;
asn1_end_tag ( & data ) ;
asn1_end_tag ( & data ) ;
asn1_start_tag ( & data , ASN1_CONTEXT ( 3 ) ) ;
asn1_start_tag ( & data , ASN1_SEQUENCE ( 0 ) ) ;
asn1_start_tag ( & data , ASN1_CONTEXT ( 0 ) ) ;
2001-10-22 00:51:27 +04:00
asn1_read_GeneralString ( & data , principal ) ;
2001-10-12 08:49:42 +04:00
asn1_end_tag ( & data ) ;
asn1_end_tag ( & data ) ;
asn1_end_tag ( & data ) ;
asn1_end_tag ( & data ) ;
asn1_end_tag ( & data ) ;
asn1_end_tag ( & data ) ;
ret = ! data . has_error ;
asn1_free ( & data ) ;
return ret ;
}
/*
generate a negTokenTarg packet given a list of OIDs and a security blob
*/
DATA_BLOB gen_negTokenTarg ( const char * OIDs [ ] , DATA_BLOB blob )
{
int i ;
ASN1_DATA data ;
DATA_BLOB ret ;
memset ( & data , 0 , sizeof ( data ) ) ;
asn1_push_tag ( & data , ASN1_APPLICATION ( 0 ) ) ;
asn1_write_OID ( & data , OID_SPNEGO ) ;
asn1_push_tag ( & data , ASN1_CONTEXT ( 0 ) ) ;
asn1_push_tag ( & data , ASN1_SEQUENCE ( 0 ) ) ;
asn1_push_tag ( & data , ASN1_CONTEXT ( 0 ) ) ;
asn1_push_tag ( & data , ASN1_SEQUENCE ( 0 ) ) ;
for ( i = 0 ; OIDs [ i ] ; i + + ) {
asn1_write_OID ( & data , OIDs [ i ] ) ;
}
asn1_pop_tag ( & data ) ;
asn1_pop_tag ( & data ) ;
asn1_push_tag ( & data , ASN1_CONTEXT ( 2 ) ) ;
asn1_write_OctetString ( & data , blob . data , blob . length ) ;
asn1_pop_tag ( & data ) ;
asn1_pop_tag ( & data ) ;
asn1_pop_tag ( & data ) ;
asn1_pop_tag ( & data ) ;
if ( data . has_error ) {
DEBUG ( 1 , ( " Failed to build negTokenTarg at offset %d \n " , ( int ) data . ofs ) ) ;
asn1_free ( & data ) ;
}
ret = data_blob ( data . data , data . length ) ;
asn1_free ( & data ) ;
return ret ;
}
2001-10-17 12:54:19 +04:00
/*
parse a negTokenTarg packet giving a list of OIDs and a security blob
*/
BOOL parse_negTokenTarg ( DATA_BLOB blob , char * OIDs [ ASN1_MAX_OIDS ] , DATA_BLOB * secblob )
{
int i ;
ASN1_DATA data ;
asn1_load ( & data , blob ) ;
asn1_start_tag ( & data , ASN1_APPLICATION ( 0 ) ) ;
asn1_check_OID ( & data , OID_SPNEGO ) ;
asn1_start_tag ( & data , ASN1_CONTEXT ( 0 ) ) ;
asn1_start_tag ( & data , ASN1_SEQUENCE ( 0 ) ) ;
asn1_start_tag ( & data , ASN1_CONTEXT ( 0 ) ) ;
asn1_start_tag ( & data , ASN1_SEQUENCE ( 0 ) ) ;
for ( i = 0 ; asn1_tag_remaining ( & data ) > 0 & & i < ASN1_MAX_OIDS ; i + + ) {
char * oid = NULL ;
asn1_read_OID ( & data , & oid ) ;
OIDs [ i ] = oid ;
}
OIDs [ i ] = NULL ;
asn1_end_tag ( & data ) ;
asn1_end_tag ( & data ) ;
asn1_start_tag ( & data , ASN1_CONTEXT ( 2 ) ) ;
asn1_read_OctetString ( & data , secblob ) ;
asn1_end_tag ( & data ) ;
asn1_end_tag ( & data ) ;
asn1_end_tag ( & data ) ;
asn1_end_tag ( & data ) ;
if ( data . has_error ) {
DEBUG ( 1 , ( " Failed to parse negTokenTarg at offset %d \n " , ( int ) data . ofs ) ) ;
asn1_free ( & data ) ;
return False ;
}
asn1_free ( & data ) ;
return True ;
}
2001-10-12 08:49:42 +04:00
/*
generate a krb5 GSS - API wrapper packet given a ticket
*/
2001-12-08 14:18:56 +03:00
DATA_BLOB spnego_gen_krb5_wrap ( DATA_BLOB ticket )
2001-10-12 08:49:42 +04:00
{
ASN1_DATA data ;
DATA_BLOB ret ;
memset ( & data , 0 , sizeof ( data ) ) ;
asn1_push_tag ( & data , ASN1_APPLICATION ( 0 ) ) ;
asn1_write_OID ( & data , OID_KERBEROS5 ) ;
asn1_write_BOOLEAN ( & data , 0 ) ;
asn1_write ( & data , ticket . data , ticket . length ) ;
asn1_pop_tag ( & data ) ;
if ( data . has_error ) {
DEBUG ( 1 , ( " Failed to build krb5 wrapper at offset %d \n " , ( int ) data . ofs ) ) ;
asn1_free ( & data ) ;
}
ret = data_blob ( data . data , data . length ) ;
asn1_free ( & data ) ;
return ret ;
}
2001-10-18 14:26:06 +04:00
/*
parse a krb5 GSS - API wrapper packet giving a ticket
*/
BOOL spnego_parse_krb5_wrap ( DATA_BLOB blob , DATA_BLOB * ticket )
{
BOOL ret ;
ASN1_DATA data ;
2002-02-16 02:11:13 +03:00
int data_remaining ;
2001-10-18 14:26:06 +04:00
asn1_load ( & data , blob ) ;
asn1_start_tag ( & data , ASN1_APPLICATION ( 0 ) ) ;
asn1_check_OID ( & data , OID_KERBEROS5 ) ;
asn1_check_BOOLEAN ( & data , 0 ) ;
2002-02-16 02:11:13 +03:00
data_remaining = asn1_tag_remaining ( & data ) ;
if ( data_remaining < 1 ) {
data . has_error = True ;
} else {
* ticket = data_blob ( data . data , data_remaining ) ;
asn1_read ( & data , ticket - > data , ticket - > length ) ;
}
2001-10-18 14:26:06 +04:00
asn1_end_tag ( & data ) ;
ret = ! data . has_error ;
asn1_free ( & data ) ;
return ret ;
}
2001-10-12 08:49:42 +04:00
/*
generate a SPNEGO negTokenTarg packet , ready for a EXTENDED_SECURITY
kerberos session setup
*/
2001-10-22 00:51:27 +04:00
DATA_BLOB spnego_gen_negTokenTarg ( struct cli_state * cli , char * principal )
2001-10-12 08:49:42 +04:00
{
DATA_BLOB tkt , tkt_wrapped , targ ;
2001-10-12 08:54:53 +04:00
const char * krb_mechs [ ] = { OID_KERBEROS5_OLD , OID_NTLMSSP , NULL } ;
2001-10-12 08:49:42 +04:00
/* get a kerberos ticket for the service */
2001-10-22 00:51:27 +04:00
tkt = krb5_get_ticket ( principal ) ;
2001-10-12 08:49:42 +04:00
/* wrap that up in a nice GSS-API wrapping */
tkt_wrapped = spnego_gen_krb5_wrap ( tkt ) ;
/* and wrap that in a shiny SPNEGO wrapper */
targ = gen_negTokenTarg ( krb_mechs , tkt_wrapped ) ;
2001-10-17 12:54:19 +04:00
data_blob_free ( & tkt_wrapped ) ;
data_blob_free ( & tkt ) ;
2001-10-12 08:49:42 +04:00
return targ ;
}
/*
parse a spnego NTLMSSP challenge packet giving two security blobs
*/
BOOL spnego_parse_challenge ( DATA_BLOB blob ,
DATA_BLOB * chal1 , DATA_BLOB * chal2 )
{
BOOL ret ;
ASN1_DATA data ;
2001-10-14 10:14:11 +04:00
ZERO_STRUCTP ( chal1 ) ;
ZERO_STRUCTP ( chal2 ) ;
2001-10-12 08:49:42 +04:00
asn1_load ( & data , blob ) ;
asn1_start_tag ( & data , ASN1_CONTEXT ( 1 ) ) ;
asn1_start_tag ( & data , ASN1_SEQUENCE ( 0 ) ) ;
asn1_start_tag ( & data , ASN1_CONTEXT ( 0 ) ) ;
asn1_check_enumerated ( & data , 1 ) ;
asn1_end_tag ( & data ) ;
asn1_start_tag ( & data , ASN1_CONTEXT ( 1 ) ) ;
2001-10-12 08:54:53 +04:00
asn1_check_OID ( & data , OID_NTLMSSP ) ;
2001-10-12 08:49:42 +04:00
asn1_end_tag ( & data ) ;
asn1_start_tag ( & data , ASN1_CONTEXT ( 2 ) ) ;
2001-10-17 12:54:19 +04:00
asn1_read_OctetString ( & data , chal1 ) ;
2001-10-12 08:49:42 +04:00
asn1_end_tag ( & data ) ;
2001-10-14 10:14:11 +04:00
/* the second challenge is optional (XP doesn't send it) */
if ( asn1_tag_remaining ( & data ) ) {
asn1_start_tag ( & data , ASN1_CONTEXT ( 3 ) ) ;
2001-10-17 12:54:19 +04:00
asn1_read_OctetString ( & data , chal2 ) ;
2001-10-14 10:14:11 +04:00
asn1_end_tag ( & data ) ;
}
2001-10-12 08:49:42 +04:00
asn1_end_tag ( & data ) ;
asn1_end_tag ( & data ) ;
ret = ! data . has_error ;
asn1_free ( & data ) ;
return ret ;
}
2001-10-17 12:54:19 +04:00
/*
generate a spnego NTLMSSP challenge packet given two security blobs
The second challenge is optional
*/
BOOL spnego_gen_challenge ( DATA_BLOB * blob ,
DATA_BLOB * chal1 , DATA_BLOB * chal2 )
{
ASN1_DATA data ;
ZERO_STRUCT ( data ) ;
asn1_push_tag ( & data , ASN1_CONTEXT ( 1 ) ) ;
asn1_push_tag ( & data , ASN1_SEQUENCE ( 0 ) ) ;
asn1_push_tag ( & data , ASN1_CONTEXT ( 0 ) ) ;
asn1_write_enumerated ( & data , 1 ) ;
asn1_pop_tag ( & data ) ;
asn1_push_tag ( & data , ASN1_CONTEXT ( 1 ) ) ;
asn1_write_OID ( & data , OID_NTLMSSP ) ;
asn1_pop_tag ( & data ) ;
asn1_push_tag ( & data , ASN1_CONTEXT ( 2 ) ) ;
asn1_write_OctetString ( & data , chal1 - > data , chal1 - > length ) ;
asn1_pop_tag ( & data ) ;
/* the second challenge is optional (XP doesn't send it) */
if ( chal2 ) {
asn1_push_tag ( & data , ASN1_CONTEXT ( 3 ) ) ;
asn1_write_OctetString ( & data , chal2 - > data , chal2 - > length ) ;
asn1_pop_tag ( & data ) ;
}
asn1_pop_tag ( & data ) ;
asn1_pop_tag ( & data ) ;
if ( data . has_error ) {
return False ;
}
* blob = data_blob ( data . data , data . length ) ;
asn1_free ( & data ) ;
return True ;
}
2001-10-12 08:49:42 +04:00
/*
generate a SPNEGO NTLMSSP auth packet . This will contain the encrypted passwords
*/
DATA_BLOB spnego_gen_auth ( DATA_BLOB blob )
{
ASN1_DATA data ;
DATA_BLOB ret ;
memset ( & data , 0 , sizeof ( data ) ) ;
asn1_push_tag ( & data , ASN1_CONTEXT ( 1 ) ) ;
asn1_push_tag ( & data , ASN1_SEQUENCE ( 0 ) ) ;
asn1_push_tag ( & data , ASN1_CONTEXT ( 2 ) ) ;
asn1_write_OctetString ( & data , blob . data , blob . length ) ;
asn1_pop_tag ( & data ) ;
asn1_pop_tag ( & data ) ;
asn1_pop_tag ( & data ) ;
ret = data_blob ( data . data , data . length ) ;
asn1_free ( & data ) ;
return ret ;
2001-10-17 12:54:19 +04:00
}
/*
parse a SPNEGO NTLMSSP auth packet . This contains the encrypted passwords
*/
BOOL spnego_parse_auth ( DATA_BLOB blob , DATA_BLOB * auth )
{
ASN1_DATA data ;
asn1_load ( & data , blob ) ;
asn1_start_tag ( & data , ASN1_CONTEXT ( 1 ) ) ;
asn1_start_tag ( & data , ASN1_SEQUENCE ( 0 ) ) ;
asn1_start_tag ( & data , ASN1_CONTEXT ( 2 ) ) ;
asn1_read_OctetString ( & data , auth ) ;
asn1_end_tag ( & data ) ;
asn1_end_tag ( & data ) ;
asn1_end_tag ( & data ) ;
if ( data . has_error ) {
DEBUG ( 3 , ( " spnego_parse_auth failed at %d \n " , ( int ) data . ofs ) ) ;
asn1_free ( & data ) ;
return False ;
}
asn1_free ( & data ) ;
return True ;
2001-10-12 08:49:42 +04:00
}
2002-08-17 21:00:51 +04:00
/*
generate a minimal SPNEGO NTLMSSP response packet . Doesn ' t contain much .
*/
DATA_BLOB spnego_gen_auth_response ( void )
{
ASN1_DATA data ;
DATA_BLOB ret ;
memset ( & data , 0 , sizeof ( data ) ) ;
asn1_push_tag ( & data , ASN1_CONTEXT ( 1 ) ) ;
asn1_push_tag ( & data , ASN1_SEQUENCE ( 0 ) ) ;
asn1_push_tag ( & data , ASN1_CONTEXT ( 0 ) ) ;
asn1_write_enumerated ( & data , 0 ) ;
asn1_pop_tag ( & data ) ;
asn1_pop_tag ( & data ) ;
asn1_pop_tag ( & data ) ;
ret = data_blob ( data . data , data . length ) ;
asn1_free ( & data ) ;
return ret ;
}
2001-10-12 08:49:42 +04:00
/*
this is a tiny msrpc packet generator . I am only using this to
avoid tying this code to a particular varient of our rpc code . This
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 )
2002-08-17 21:00:51 +04:00
a = address ( 1 byte type , 1 byte length , unicode string , all inline )
2001-10-12 08:49:42 +04:00
B = data blob ( pointer + length )
2001-10-17 12:54:19 +04:00
b = data blob in header ( pointer + length )
2001-10-12 08:49:42 +04:00
d = word ( 4 bytes )
C = constant ascii string
*/
BOOL msrpc_gen ( DATA_BLOB * blob ,
const char * format , . . . )
{
int i , n ;
va_list ap ;
char * s ;
uint8 * b ;
int head_size = 0 , data_size = 0 ;
int head_ofs , data_ofs ;
/* 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 ;
data_size + = str_charnum ( s ) * 2 ;
break ;
2002-08-17 21:00:51 +04:00
case ' a ' :
n = va_arg ( ap , int ) ;
s = va_arg ( ap , char * ) ;
data_size + = ( str_charnum ( s ) * 2 ) + 4 ;
break ;
2001-10-12 08:49:42 +04:00
case ' B ' :
b = va_arg ( ap , uint8 * ) ;
head_size + = 8 ;
data_size + = va_arg ( ap , int ) ;
break ;
2001-10-17 12:54:19 +04:00
case ' b ' :
b = va_arg ( ap , uint8 * ) ;
head_size + = va_arg ( ap , int ) ;
break ;
2001-10-12 08:49:42 +04:00
case ' d ' :
n = va_arg ( ap , int ) ;
head_size + = 4 ;
break ;
case ' C ' :
s = va_arg ( ap , char * ) ;
head_size + = str_charnum ( s ) + 1 ;
break ;
}
}
va_end ( ap ) ;
/* allocate the space, then scan the format again to fill in the values */
2002-01-06 02:30:59 +03:00
* blob = data_blob ( NULL , head_size + data_size ) ;
2001-10-12 08:49:42 +04:00
head_ofs = 0 ;
data_ofs = head_size ;
va_start ( ap , format ) ;
for ( i = 0 ; format [ i ] ; i + + ) {
switch ( format [ i ] ) {
case ' U ' :
s = va_arg ( ap , char * ) ;
n = str_charnum ( s ) ;
SSVAL ( blob - > data , head_ofs , n * 2 ) ; head_ofs + = 2 ;
SSVAL ( blob - > data , head_ofs , n * 2 ) ; head_ofs + = 2 ;
SIVAL ( blob - > data , head_ofs , data_ofs ) ; head_ofs + = 4 ;
push_string ( NULL , blob - > data + data_ofs , s , n * 2 , STR_UNICODE | STR_NOALIGN ) ;
data_ofs + = n * 2 ;
break ;
2002-08-17 21:00:51 +04:00
case ' a ' :
n = va_arg ( ap , int ) ;
SSVAL ( blob - > data , data_ofs , n ) ; data_ofs + = 2 ;
s = va_arg ( ap , char * ) ;
n = str_charnum ( s ) ;
SSVAL ( blob - > data , data_ofs , n * 2 ) ; data_ofs + = 2 ;
if ( 0 < n ) {
push_string ( NULL , blob - > data + data_ofs , s , n * 2 ,
STR_UNICODE | STR_NOALIGN ) ;
}
data_ofs + = n * 2 ;
break ;
2001-10-12 08:49:42 +04:00
case ' B ' :
b = va_arg ( ap , uint8 * ) ;
n = va_arg ( ap , int ) ;
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 ;
memcpy ( blob - > data + data_ofs , b , n ) ;
data_ofs + = n ;
break ;
case ' d ' :
n = va_arg ( ap , int ) ;
SIVAL ( blob - > data , head_ofs , n ) ; head_ofs + = 4 ;
break ;
2001-10-17 12:54:19 +04:00
case ' b ' :
b = va_arg ( ap , uint8 * ) ;
n = va_arg ( ap , int ) ;
memcpy ( blob - > data + head_ofs , b , n ) ;
head_ofs + = n ;
break ;
2001-10-12 08:49:42 +04:00
case ' C ' :
s = va_arg ( ap , char * ) ;
head_ofs + = push_string ( NULL , blob - > data + head_ofs , s , - 1 ,
STR_ASCII | STR_TERMINATE ) ;
break ;
}
}
va_end ( ap ) ;
return True ;
}
2001-10-17 12:54:19 +04:00
/*
this is a tiny msrpc packet parser . This the the partner of msrpc_gen
format specifiers are :
2002-07-15 14:35:28 +04:00
U = unicode string ( output is unix string )
2002-08-17 21:00:51 +04:00
A = ascii string
2001-10-17 12:54:19 +04:00
B = data blob
b = data blob in header
d = word ( 4 bytes )
C = constant ascii string
*/
BOOL msrpc_parse ( DATA_BLOB * blob ,
const char * format , . . . )
{
int i ;
va_list ap ;
char * * ps , * s ;
DATA_BLOB * b ;
int head_ofs = 0 ;
uint16 len1 , len2 ;
uint32 ptr ;
uint32 * v ;
pstring p ;
va_start ( ap , format ) ;
for ( i = 0 ; format [ i ] ; i + + ) {
switch ( format [ i ] ) {
case ' U ' :
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 ;
/* make sure its in the right format - be strict */
if ( len1 ! = len2 | | ( len1 & 1 ) | | ptr + len1 > blob - > length ) {
return False ;
}
ps = va_arg ( ap , char * * ) ;
pull_string ( NULL , p , blob - > data + ptr , - 1 , len1 ,
STR_UNICODE | STR_NOALIGN ) ;
( * ps ) = strdup ( p ) ;
break ;
2002-08-17 21:00:51 +04:00
case ' A ' :
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 ;
/* make sure its in the right format - be strict */
if ( len1 ! = len2 | | ptr + len1 > blob - > length ) {
return False ;
}
ps = va_arg ( ap , char * * ) ;
if ( 0 < len1 ) {
pull_string ( NULL , p , blob - > data + ptr , - 1 ,
len1 , STR_ASCII | STR_NOALIGN ) ;
( * ps ) = strdup ( p ) ;
} else {
( * ps ) = NULL ;
}
break ;
2001-10-17 12:54:19 +04:00
case ' B ' :
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 ;
/* make sure its in the right format - be strict */
if ( len1 ! = len2 | | ptr + len1 > blob - > length ) {
return False ;
}
b = ( DATA_BLOB * ) va_arg ( ap , void * ) ;
* b = data_blob ( blob - > data + ptr , len1 ) ;
break ;
case ' b ' :
b = ( DATA_BLOB * ) va_arg ( ap , void * ) ;
len1 = va_arg ( ap , unsigned ) ;
* b = data_blob ( blob - > data + head_ofs , len1 ) ;
head_ofs + = len1 ;
break ;
case ' d ' :
v = va_arg ( ap , uint32 * ) ;
* v = IVAL ( blob - > data , head_ofs ) ; head_ofs + = 4 ;
break ;
case ' C ' :
s = va_arg ( ap , char * ) ;
head_ofs + = pull_string ( NULL , p , blob - > data + head_ofs , - 1 ,
blob - > length - head_ofs ,
STR_ASCII | STR_TERMINATE ) ;
if ( strcmp ( s , p ) ! = 0 ) {
return False ;
}
break ;
}
}
va_end ( ap ) ;
return True ;
}
2002-07-15 14:35:28 +04:00
/**
* Print out the NTLMSSP flags for debugging
*/
void debug_ntlmssp_flags ( uint32 neg_flags )
{
if ( neg_flags & NTLMSSP_NEGOTIATE_UNICODE )
DEBUG ( 4 , ( " NTLMSSP_NEGOTIATE_UNICODE \n " ) ) ;
if ( neg_flags & NTLMSSP_NEGOTIATE_OEM )
DEBUG ( 4 , ( " NTLMSSP_NEGOTIATE_OEM \n " ) ) ;
if ( neg_flags & NTLMSSP_REQUEST_TARGET )
DEBUG ( 4 , ( " NTLMSSP_REQUEST_TARGET \n " ) ) ;
if ( neg_flags & NTLMSSP_NEGOTIATE_SIGN )
DEBUG ( 4 , ( " NTLMSSP_NEGOTIATE_SIGN \n " ) ) ;
if ( neg_flags & NTLMSSP_NEGOTIATE_SIGN )
DEBUG ( 4 , ( " NTLMSSP_NEGOTIATE_SEAL \n " ) ) ;
if ( neg_flags & NTLMSSP_NEGOTIATE_LM_KEY )
DEBUG ( 4 , ( " NTLMSSP_NEGOTIATE_LM_KEY \n " ) ) ;
if ( neg_flags & NTLMSSP_NEGOTIATE_NETWARE )
DEBUG ( 4 , ( " NTLMSSP_NEGOTIATE_NETWARE \n " ) ) ;
if ( neg_flags & NTLMSSP_NEGOTIATE_NTLM )
DEBUG ( 4 , ( " NTLMSSP_NEGOTIATE_NTLM \n " ) ) ;
if ( neg_flags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED )
DEBUG ( 4 , ( " NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED \n " ) ) ;
if ( neg_flags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED )
DEBUG ( 4 , ( " NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED \n " ) ) ;
if ( neg_flags & NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL )
DEBUG ( 4 , ( " NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL \n " ) ) ;
if ( neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN )
DEBUG ( 4 , ( " NTLMSSP_NEGOTIATE_ALWAYS_SIGN \n " ) ) ;
if ( neg_flags & NTLMSSP_NEGOTIATE_NTLM2 )
DEBUG ( 4 , ( " NTLMSSP_NEGOTIATE_NTLM2 \n " ) ) ;
if ( neg_flags & NTLMSSP_CHAL_TARGET_INFO )
DEBUG ( 4 , ( " NTLMSSP_CHAL_TARGET_INFO \n " ) ) ;
if ( neg_flags & NTLMSSP_NEGOTIATE_128 )
DEBUG ( 4 , ( " NTLMSSP_NEGOTIATE_128 \n " ) ) ;
if ( neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH )
DEBUG ( 4 , ( " NTLMSSP_NEGOTIATE_KEY_EXCH \n " ) ) ;
}