2003-11-03 06:22:45 +00:00
/*
Unix SMB / CIFS implementation .
raw dcerpc operations
Copyright ( C ) Tim Potter 2003
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"
/* initialise a dcerpc pipe. This currently assumes a SMB named pipe
transport */
2003-11-24 12:40:47 +00:00
struct dcerpc_pipe * dcerpc_pipe_init ( void )
2003-11-03 06:22:45 +00:00
{
struct dcerpc_pipe * p ;
2003-11-04 09:10:31 +00:00
TALLOC_CTX * mem_ctx = talloc_init ( " dcerpc_tree " ) ;
2003-11-03 06:22:45 +00:00
if ( mem_ctx = = NULL )
return NULL ;
p = talloc ( mem_ctx , sizeof ( * p ) ) ;
if ( ! p ) {
talloc_destroy ( mem_ctx ) ;
return NULL ;
}
2003-11-04 22:42:00 +00:00
p - > reference_count = 0 ;
2003-11-03 06:22:45 +00:00
p - > mem_ctx = mem_ctx ;
p - > call_id = 1 ;
2004-06-07 12:30:22 +00:00
p - > security_state . auth_info = NULL ;
r1294: A nice, large, commit...
This implements gensec for Samba's server side, and brings gensec up
to the standards of a full subsystem.
This means that use of the subsystem is by gensec_* functions, not
function pointers in structures (this is internal). This causes
changes in all the existing gensec users.
Our RPC server no longer contains it's own generalised security
scheme, and now calls gensec directly.
Gensec has also taken over the role of auth/auth_ntlmssp.c
An important part of gensec, is the output of the 'session_info'
struct. This is now reference counted, so that we can correctly free
it when a pipe is closed, no matter if it was inherited, or created by
per-pipe authentication.
The schannel code is reworked, to be in the same file for client and
server.
ntlm_auth is reworked to use gensec.
The major problem with this code is the way it relies on subsystem
auto-initialisation. The primary reason for this commit now.is to
allow these problems to be looked at, and fixed.
There are problems with the new code:
- I've tested it with smbtorture, but currently don't have VMware and
valgrind working (this I'll fix soon).
- The SPNEGO code is client-only at this point.
- We still do not do kerberos.
Andrew Bartlett
(This used to be commit 07fd885fd488fd1051eacc905a2d4962f8a018ec)
2004-06-29 09:40:10 +00:00
p - > security_state . generic_state = NULL ;
2004-06-07 21:30:17 +00:00
p - > binding_string = NULL ;
2003-11-26 03:36:17 +00:00
p - > flags = 0 ;
2003-11-27 04:02:15 +00:00
p - > srv_max_xmit_frag = 0 ;
p - > srv_max_recv_frag = 0 ;
2004-06-07 21:30:17 +00:00
p - > last_fault_code = 0 ;
2003-11-03 06:22:45 +00:00
return p ;
}
/* close down a dcerpc over SMB pipe */
void dcerpc_pipe_close ( struct dcerpc_pipe * p )
{
if ( ! p ) return ;
p - > reference_count - - ;
if ( p - > reference_count < = 0 ) {
r1294: A nice, large, commit...
This implements gensec for Samba's server side, and brings gensec up
to the standards of a full subsystem.
This means that use of the subsystem is by gensec_* functions, not
function pointers in structures (this is internal). This causes
changes in all the existing gensec users.
Our RPC server no longer contains it's own generalised security
scheme, and now calls gensec directly.
Gensec has also taken over the role of auth/auth_ntlmssp.c
An important part of gensec, is the output of the 'session_info'
struct. This is now reference counted, so that we can correctly free
it when a pipe is closed, no matter if it was inherited, or created by
per-pipe authentication.
The schannel code is reworked, to be in the same file for client and
server.
ntlm_auth is reworked to use gensec.
The major problem with this code is the way it relies on subsystem
auto-initialisation. The primary reason for this commit now.is to
allow these problems to be looked at, and fixed.
There are problems with the new code:
- I've tested it with smbtorture, but currently don't have VMware and
valgrind working (this I'll fix soon).
- The SPNEGO code is client-only at this point.
- We still do not do kerberos.
Andrew Bartlett
(This used to be commit 07fd885fd488fd1051eacc905a2d4962f8a018ec)
2004-06-29 09:40:10 +00:00
if ( p - > security_state . generic_state ) {
gensec_end ( & p - > security_state . generic_state ) ;
2003-11-26 02:08:41 +00:00
}
2003-11-24 11:45:33 +00:00
p - > transport . shutdown_pipe ( p ) ;
2003-11-03 06:22:45 +00:00
talloc_destroy ( p - > mem_ctx ) ;
}
}
2003-12-16 09:02:58 +00:00
/* we need to be able to get/set the fragment length without doing a full
decode */
2004-05-25 17:24:24 +00:00
void dcerpc_set_frag_length ( DATA_BLOB * blob , uint16_t v )
2003-12-16 09:02:58 +00:00
{
2003-12-16 11:24:28 +00:00
if ( CVAL ( blob - > data , DCERPC_DREP_OFFSET ) & DCERPC_DREP_LE ) {
2003-12-16 09:02:58 +00:00
SSVAL ( blob - > data , DCERPC_FRAG_LEN_OFFSET , v ) ;
} else {
RSSVAL ( blob - > data , DCERPC_FRAG_LEN_OFFSET , v ) ;
}
}
2004-05-25 17:24:24 +00:00
uint16_t dcerpc_get_frag_length ( const DATA_BLOB * blob )
2003-12-16 09:02:58 +00:00
{
2003-12-16 11:24:28 +00:00
if ( CVAL ( blob - > data , DCERPC_DREP_OFFSET ) & DCERPC_DREP_LE ) {
2003-12-16 09:02:58 +00:00
return SVAL ( blob - > data , DCERPC_FRAG_LEN_OFFSET ) ;
} else {
return RSVAL ( blob - > data , DCERPC_FRAG_LEN_OFFSET ) ;
}
}
2004-05-25 17:24:24 +00:00
void dcerpc_set_auth_length ( DATA_BLOB * blob , uint16_t v )
2003-12-16 09:02:58 +00:00
{
2003-12-16 11:24:28 +00:00
if ( CVAL ( blob - > data , DCERPC_DREP_OFFSET ) & DCERPC_DREP_LE ) {
2003-12-16 09:02:58 +00:00
SSVAL ( blob - > data , DCERPC_AUTH_LEN_OFFSET , v ) ;
} else {
RSSVAL ( blob - > data , DCERPC_AUTH_LEN_OFFSET , v ) ;
}
}
2003-11-03 06:22:45 +00:00
/*
parse a data blob into a dcerpc_packet structure . This handles both
input and output packets
*/
2003-11-26 01:16:41 +00:00
static NTSTATUS dcerpc_pull ( DATA_BLOB * blob , TALLOC_CTX * mem_ctx ,
struct dcerpc_packet * pkt )
2003-11-03 06:22:45 +00:00
{
2003-11-23 06:28:12 +00:00
struct ndr_pull * ndr ;
2003-11-03 06:22:45 +00:00
2003-11-23 06:28:12 +00:00
ndr = ndr_pull_init_blob ( blob , mem_ctx ) ;
if ( ! ndr ) {
return NT_STATUS_NO_MEMORY ;
2003-11-03 06:22:45 +00:00
}
2003-12-17 02:06:44 +00:00
if ( ! ( CVAL ( blob - > data , DCERPC_DREP_OFFSET ) & DCERPC_DREP_LE ) ) {
ndr - > flags | = LIBNDR_FLAG_BIGENDIAN ;
2003-12-16 09:02:58 +00:00
}
2003-11-23 06:28:12 +00:00
return ndr_pull_dcerpc_packet ( ndr , NDR_SCALARS | NDR_BUFFERS , pkt ) ;
2003-11-03 06:22:45 +00:00
}
2003-11-26 01:16:41 +00:00
/*
parse a possibly signed blob into a dcerpc request packet structure
*/
static NTSTATUS dcerpc_pull_request_sign ( struct dcerpc_pipe * p ,
DATA_BLOB * blob , TALLOC_CTX * mem_ctx ,
struct dcerpc_packet * pkt )
{
struct ndr_pull * ndr ;
NTSTATUS status ;
struct dcerpc_auth auth ;
DATA_BLOB auth_blob ;
/* non-signed packets are simpler */
r1294: A nice, large, commit...
This implements gensec for Samba's server side, and brings gensec up
to the standards of a full subsystem.
This means that use of the subsystem is by gensec_* functions, not
function pointers in structures (this is internal). This causes
changes in all the existing gensec users.
Our RPC server no longer contains it's own generalised security
scheme, and now calls gensec directly.
Gensec has also taken over the role of auth/auth_ntlmssp.c
An important part of gensec, is the output of the 'session_info'
struct. This is now reference counted, so that we can correctly free
it when a pipe is closed, no matter if it was inherited, or created by
per-pipe authentication.
The schannel code is reworked, to be in the same file for client and
server.
ntlm_auth is reworked to use gensec.
The major problem with this code is the way it relies on subsystem
auto-initialisation. The primary reason for this commit now.is to
allow these problems to be looked at, and fixed.
There are problems with the new code:
- I've tested it with smbtorture, but currently don't have VMware and
valgrind working (this I'll fix soon).
- The SPNEGO code is client-only at this point.
- We still do not do kerberos.
Andrew Bartlett
(This used to be commit 07fd885fd488fd1051eacc905a2d4962f8a018ec)
2004-06-29 09:40:10 +00:00
if ( ! p - > security_state . auth_info | | ! p - > security_state . generic_state ) {
2003-11-26 01:16:41 +00:00
return dcerpc_pull ( blob , mem_ctx , pkt ) ;
}
ndr = ndr_pull_init_blob ( blob , mem_ctx ) ;
if ( ! ndr ) {
return NT_STATUS_NO_MEMORY ;
}
2003-12-17 02:06:44 +00:00
if ( ! ( CVAL ( blob - > data , DCERPC_DREP_OFFSET ) & DCERPC_DREP_LE ) ) {
ndr - > flags | = LIBNDR_FLAG_BIGENDIAN ;
2003-12-16 09:02:58 +00:00
}
2003-11-26 01:16:41 +00:00
/* pull the basic packet */
status = ndr_pull_dcerpc_packet ( ndr , NDR_SCALARS | NDR_BUFFERS , pkt ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
if ( pkt - > ptype ! = DCERPC_PKT_RESPONSE ) {
return status ;
}
auth_blob . length = 8 + pkt - > auth_length ;
/* check for a valid length */
if ( pkt - > u . response . stub_and_verifier . length < auth_blob . length ) {
return NT_STATUS_INFO_LENGTH_MISMATCH ;
}
auth_blob . data =
pkt - > u . response . stub_and_verifier . data +
pkt - > u . response . stub_and_verifier . length - auth_blob . length ;
pkt - > u . response . stub_and_verifier . length - = auth_blob . length ;
/* pull the auth structure */
ndr = ndr_pull_init_blob ( & auth_blob , mem_ctx ) ;
if ( ! ndr ) {
return NT_STATUS_NO_MEMORY ;
}
2003-12-17 02:06:44 +00:00
if ( ! ( CVAL ( blob - > data , DCERPC_DREP_OFFSET ) & DCERPC_DREP_LE ) ) {
ndr - > flags | = LIBNDR_FLAG_BIGENDIAN ;
2003-12-16 09:02:58 +00:00
}
2003-11-26 01:16:41 +00:00
status = ndr_pull_dcerpc_auth ( ndr , NDR_SCALARS | NDR_BUFFERS , & auth ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2003-11-26 12:29:08 +00:00
/* check signature or unseal the packet */
2004-06-07 12:30:22 +00:00
switch ( p - > security_state . auth_info - > auth_level ) {
2003-11-26 12:29:08 +00:00
case DCERPC_AUTH_LEVEL_PRIVACY :
r1294: A nice, large, commit...
This implements gensec for Samba's server side, and brings gensec up
to the standards of a full subsystem.
This means that use of the subsystem is by gensec_* functions, not
function pointers in structures (this is internal). This causes
changes in all the existing gensec users.
Our RPC server no longer contains it's own generalised security
scheme, and now calls gensec directly.
Gensec has also taken over the role of auth/auth_ntlmssp.c
An important part of gensec, is the output of the 'session_info'
struct. This is now reference counted, so that we can correctly free
it when a pipe is closed, no matter if it was inherited, or created by
per-pipe authentication.
The schannel code is reworked, to be in the same file for client and
server.
ntlm_auth is reworked to use gensec.
The major problem with this code is the way it relies on subsystem
auto-initialisation. The primary reason for this commit now.is to
allow these problems to be looked at, and fixed.
There are problems with the new code:
- I've tested it with smbtorture, but currently don't have VMware and
valgrind working (this I'll fix soon).
- The SPNEGO code is client-only at this point.
- We still do not do kerberos.
Andrew Bartlett
(This used to be commit 07fd885fd488fd1051eacc905a2d4962f8a018ec)
2004-06-29 09:40:10 +00:00
status = gensec_unseal_packet ( p - > security_state . generic_state ,
mem_ctx ,
pkt - > u . response . stub_and_verifier . data ,
pkt - > u . response . stub_and_verifier . length ,
& auth . credentials ) ;
2003-11-26 12:29:08 +00:00
break ;
r1294: A nice, large, commit...
This implements gensec for Samba's server side, and brings gensec up
to the standards of a full subsystem.
This means that use of the subsystem is by gensec_* functions, not
function pointers in structures (this is internal). This causes
changes in all the existing gensec users.
Our RPC server no longer contains it's own generalised security
scheme, and now calls gensec directly.
Gensec has also taken over the role of auth/auth_ntlmssp.c
An important part of gensec, is the output of the 'session_info'
struct. This is now reference counted, so that we can correctly free
it when a pipe is closed, no matter if it was inherited, or created by
per-pipe authentication.
The schannel code is reworked, to be in the same file for client and
server.
ntlm_auth is reworked to use gensec.
The major problem with this code is the way it relies on subsystem
auto-initialisation. The primary reason for this commit now.is to
allow these problems to be looked at, and fixed.
There are problems with the new code:
- I've tested it with smbtorture, but currently don't have VMware and
valgrind working (this I'll fix soon).
- The SPNEGO code is client-only at this point.
- We still do not do kerberos.
Andrew Bartlett
(This used to be commit 07fd885fd488fd1051eacc905a2d4962f8a018ec)
2004-06-29 09:40:10 +00:00
2003-11-26 12:29:08 +00:00
case DCERPC_AUTH_LEVEL_INTEGRITY :
r1294: A nice, large, commit...
This implements gensec for Samba's server side, and brings gensec up
to the standards of a full subsystem.
This means that use of the subsystem is by gensec_* functions, not
function pointers in structures (this is internal). This causes
changes in all the existing gensec users.
Our RPC server no longer contains it's own generalised security
scheme, and now calls gensec directly.
Gensec has also taken over the role of auth/auth_ntlmssp.c
An important part of gensec, is the output of the 'session_info'
struct. This is now reference counted, so that we can correctly free
it when a pipe is closed, no matter if it was inherited, or created by
per-pipe authentication.
The schannel code is reworked, to be in the same file for client and
server.
ntlm_auth is reworked to use gensec.
The major problem with this code is the way it relies on subsystem
auto-initialisation. The primary reason for this commit now.is to
allow these problems to be looked at, and fixed.
There are problems with the new code:
- I've tested it with smbtorture, but currently don't have VMware and
valgrind working (this I'll fix soon).
- The SPNEGO code is client-only at this point.
- We still do not do kerberos.
Andrew Bartlett
(This used to be commit 07fd885fd488fd1051eacc905a2d4962f8a018ec)
2004-06-29 09:40:10 +00:00
status = gensec_check_packet ( p - > security_state . generic_state ,
mem_ctx ,
pkt - > u . response . stub_and_verifier . data ,
pkt - > u . response . stub_and_verifier . length ,
& auth . credentials ) ;
2003-11-26 12:29:08 +00:00
break ;
case DCERPC_AUTH_LEVEL_NONE :
break ;
default :
status = NT_STATUS_INVALID_LEVEL ;
break ;
}
2003-11-26 01:16:41 +00:00
/* remove the indicated amount of paddiing */
if ( pkt - > u . response . stub_and_verifier . length < auth . auth_pad_length ) {
return NT_STATUS_INFO_LENGTH_MISMATCH ;
}
pkt - > u . response . stub_and_verifier . length - = auth . auth_pad_length ;
return status ;
}
2003-11-03 06:22:45 +00:00
2003-11-26 01:16:41 +00:00
/*
push a dcerpc request packet into a blob , possibly signing it .
*/
static NTSTATUS dcerpc_push_request_sign ( struct dcerpc_pipe * p ,
DATA_BLOB * blob , TALLOC_CTX * mem_ctx ,
struct dcerpc_packet * pkt )
{
NTSTATUS status ;
struct ndr_push * ndr ;
/* non-signed packets are simpler */
r1294: A nice, large, commit...
This implements gensec for Samba's server side, and brings gensec up
to the standards of a full subsystem.
This means that use of the subsystem is by gensec_* functions, not
function pointers in structures (this is internal). This causes
changes in all the existing gensec users.
Our RPC server no longer contains it's own generalised security
scheme, and now calls gensec directly.
Gensec has also taken over the role of auth/auth_ntlmssp.c
An important part of gensec, is the output of the 'session_info'
struct. This is now reference counted, so that we can correctly free
it when a pipe is closed, no matter if it was inherited, or created by
per-pipe authentication.
The schannel code is reworked, to be in the same file for client and
server.
ntlm_auth is reworked to use gensec.
The major problem with this code is the way it relies on subsystem
auto-initialisation. The primary reason for this commit now.is to
allow these problems to be looked at, and fixed.
There are problems with the new code:
- I've tested it with smbtorture, but currently don't have VMware and
valgrind working (this I'll fix soon).
- The SPNEGO code is client-only at this point.
- We still do not do kerberos.
Andrew Bartlett
(This used to be commit 07fd885fd488fd1051eacc905a2d4962f8a018ec)
2004-06-29 09:40:10 +00:00
if ( ! p - > security_state . auth_info | | ! p - > security_state . generic_state ) {
2004-06-07 12:30:22 +00:00
return dcerpc_push_auth ( blob , mem_ctx , pkt , p - > security_state . auth_info ) ;
2003-11-26 01:16:41 +00:00
}
ndr = ndr_push_init_ctx ( mem_ctx ) ;
if ( ! ndr ) {
return NT_STATUS_NO_MEMORY ;
}
2003-12-16 09:02:58 +00:00
if ( p - > flags & DCERPC_PUSH_BIGENDIAN ) {
ndr - > flags | = LIBNDR_FLAG_BIGENDIAN ;
}
2003-11-26 01:16:41 +00:00
status = ndr_push_dcerpc_packet ( ndr , NDR_SCALARS | NDR_BUFFERS , pkt ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2004-08-24 23:56:59 +00:00
/* pad to 16 byte multiple in the payload portion of the
packet . This matches what w2k3 does */
p - > security_state . auth_info - > auth_pad_length =
( 16 - ( pkt - > u . request . stub_and_verifier . length & 15 ) ) & 15 ;
2004-06-07 12:30:22 +00:00
ndr_push_zero ( ndr , p - > security_state . auth_info - > auth_pad_length ) ;
2003-11-26 01:16:41 +00:00
2003-11-26 12:29:08 +00:00
/* sign or seal the packet */
2004-06-07 12:30:22 +00:00
switch ( p - > security_state . auth_info - > auth_level ) {
2003-11-26 12:29:08 +00:00
case DCERPC_AUTH_LEVEL_PRIVACY :
r1294: A nice, large, commit...
This implements gensec for Samba's server side, and brings gensec up
to the standards of a full subsystem.
This means that use of the subsystem is by gensec_* functions, not
function pointers in structures (this is internal). This causes
changes in all the existing gensec users.
Our RPC server no longer contains it's own generalised security
scheme, and now calls gensec directly.
Gensec has also taken over the role of auth/auth_ntlmssp.c
An important part of gensec, is the output of the 'session_info'
struct. This is now reference counted, so that we can correctly free
it when a pipe is closed, no matter if it was inherited, or created by
per-pipe authentication.
The schannel code is reworked, to be in the same file for client and
server.
ntlm_auth is reworked to use gensec.
The major problem with this code is the way it relies on subsystem
auto-initialisation. The primary reason for this commit now.is to
allow these problems to be looked at, and fixed.
There are problems with the new code:
- I've tested it with smbtorture, but currently don't have VMware and
valgrind working (this I'll fix soon).
- The SPNEGO code is client-only at this point.
- We still do not do kerberos.
Andrew Bartlett
(This used to be commit 07fd885fd488fd1051eacc905a2d4962f8a018ec)
2004-06-29 09:40:10 +00:00
status = gensec_seal_packet ( p - > security_state . generic_state ,
mem_ctx ,
ndr - > data + DCERPC_REQUEST_LENGTH ,
ndr - > offset - DCERPC_REQUEST_LENGTH ,
& p - > security_state . auth_info - > credentials ) ;
2003-11-26 12:29:08 +00:00
break ;
case DCERPC_AUTH_LEVEL_INTEGRITY :
r1294: A nice, large, commit...
This implements gensec for Samba's server side, and brings gensec up
to the standards of a full subsystem.
This means that use of the subsystem is by gensec_* functions, not
function pointers in structures (this is internal). This causes
changes in all the existing gensec users.
Our RPC server no longer contains it's own generalised security
scheme, and now calls gensec directly.
Gensec has also taken over the role of auth/auth_ntlmssp.c
An important part of gensec, is the output of the 'session_info'
struct. This is now reference counted, so that we can correctly free
it when a pipe is closed, no matter if it was inherited, or created by
per-pipe authentication.
The schannel code is reworked, to be in the same file for client and
server.
ntlm_auth is reworked to use gensec.
The major problem with this code is the way it relies on subsystem
auto-initialisation. The primary reason for this commit now.is to
allow these problems to be looked at, and fixed.
There are problems with the new code:
- I've tested it with smbtorture, but currently don't have VMware and
valgrind working (this I'll fix soon).
- The SPNEGO code is client-only at this point.
- We still do not do kerberos.
Andrew Bartlett
(This used to be commit 07fd885fd488fd1051eacc905a2d4962f8a018ec)
2004-06-29 09:40:10 +00:00
status = gensec_sign_packet ( p - > security_state . generic_state ,
mem_ctx ,
ndr - > data + DCERPC_REQUEST_LENGTH ,
ndr - > offset - DCERPC_REQUEST_LENGTH ,
& p - > security_state . auth_info - > credentials ) ;
2003-11-26 12:29:08 +00:00
break ;
case DCERPC_AUTH_LEVEL_NONE :
2004-06-07 12:30:22 +00:00
p - > security_state . auth_info - > credentials = data_blob ( NULL , 0 ) ;
2003-11-26 12:29:08 +00:00
break ;
default :
status = NT_STATUS_INVALID_LEVEL ;
break ;
}
2003-11-26 01:16:41 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/* add the auth verifier */
2004-06-07 12:30:22 +00:00
status = ndr_push_dcerpc_auth ( ndr , NDR_SCALARS | NDR_BUFFERS , p - > security_state . auth_info ) ;
2003-11-26 01:16:41 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/* extract the whole packet as a blob */
* blob = ndr_push_blob ( ndr ) ;
2003-11-26 03:36:17 +00:00
/* fill in the fragment length and auth_length, we can't fill
in these earlier as we don ' t know the signature length ( it
could be variable length ) */
2003-12-16 09:02:58 +00:00
dcerpc_set_frag_length ( blob , blob - > length ) ;
2004-06-07 12:30:22 +00:00
dcerpc_set_auth_length ( blob , p - > security_state . auth_info - > credentials . length ) ;
2003-11-26 01:16:41 +00:00
2004-06-07 12:30:22 +00:00
data_blob_free ( & p - > security_state . auth_info - > credentials ) ;
2003-11-26 02:08:41 +00:00
2003-11-26 01:16:41 +00:00
return NT_STATUS_OK ;
2003-11-03 06:22:45 +00:00
}
/*
fill in the fixed values in a dcerpc header
*/
2003-12-16 09:02:58 +00:00
static void init_dcerpc_hdr ( struct dcerpc_pipe * p , struct dcerpc_packet * pkt )
2003-11-03 06:22:45 +00:00
{
2003-11-23 06:28:12 +00:00
pkt - > rpc_vers = 5 ;
pkt - > rpc_vers_minor = 0 ;
2003-12-16 09:02:58 +00:00
if ( p - > flags & DCERPC_PUSH_BIGENDIAN ) {
pkt - > drep [ 0 ] = 0 ;
} else {
2003-12-16 11:24:28 +00:00
pkt - > drep [ 0 ] = DCERPC_DREP_LE ;
2003-12-16 09:02:58 +00:00
}
2003-11-23 06:28:12 +00:00
pkt - > drep [ 1 ] = 0 ;
pkt - > drep [ 2 ] = 0 ;
pkt - > drep [ 3 ] = 0 ;
2003-11-03 06:22:45 +00:00
}
/*
perform a bind using the given syntax
2003-11-26 01:16:41 +00:00
the auth_info structure is updated with the reply authentication info
on success
2003-11-03 06:22:45 +00:00
*/
NTSTATUS dcerpc_bind ( struct dcerpc_pipe * p ,
2003-11-26 01:16:41 +00:00
TALLOC_CTX * mem_ctx ,
2003-11-03 06:22:45 +00:00
const struct dcerpc_syntax_id * syntax ,
const struct dcerpc_syntax_id * transfer_syntax )
{
2003-11-23 06:28:12 +00:00
struct dcerpc_packet pkt ;
2003-11-03 06:22:45 +00:00
NTSTATUS status ;
DATA_BLOB blob ;
2004-07-09 12:26:34 +00:00
p - > syntax = * syntax ;
p - > transfer_syntax = * transfer_syntax ;
2003-11-03 06:22:45 +00:00
2003-12-16 09:02:58 +00:00
init_dcerpc_hdr ( p , & pkt ) ;
2003-11-03 06:22:45 +00:00
2003-11-23 06:28:12 +00:00
pkt . ptype = DCERPC_PKT_BIND ;
pkt . pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST ;
2003-11-26 01:16:41 +00:00
pkt . call_id = p - > call_id ;
2003-11-23 06:28:12 +00:00
pkt . auth_length = 0 ;
2003-11-03 06:22:45 +00:00
2003-11-23 06:28:12 +00:00
pkt . u . bind . max_xmit_frag = 0x2000 ;
pkt . u . bind . max_recv_frag = 0x2000 ;
pkt . u . bind . assoc_group_id = 0 ;
pkt . u . bind . num_contexts = 1 ;
pkt . u . bind . ctx_list = talloc ( mem_ctx , sizeof ( pkt . u . bind . ctx_list [ 0 ] ) ) ;
if ( ! pkt . u . bind . ctx_list ) {
2003-11-03 06:22:45 +00:00
return NT_STATUS_NO_MEMORY ;
}
2003-11-23 06:28:12 +00:00
pkt . u . bind . ctx_list [ 0 ] . context_id = 0 ;
pkt . u . bind . ctx_list [ 0 ] . num_transfer_syntaxes = 1 ;
2004-07-09 12:26:34 +00:00
pkt . u . bind . ctx_list [ 0 ] . abstract_syntax = p - > syntax ;
pkt . u . bind . ctx_list [ 0 ] . transfer_syntaxes = & p - > transfer_syntax ;
2003-11-26 01:16:41 +00:00
pkt . u . bind . auth_info = data_blob ( NULL , 0 ) ;
2003-11-03 06:22:45 +00:00
2003-11-26 01:16:41 +00:00
/* construct the NDR form of the packet */
2004-06-07 12:30:22 +00:00
status = dcerpc_push_auth ( & blob , mem_ctx , & pkt , p - > security_state . auth_info ) ;
2003-11-03 06:22:45 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2003-11-26 01:16:41 +00:00
/* send it on its way */
status = p - > transport . full_request ( p , mem_ctx , & blob , & blob ) ;
2003-11-03 06:22:45 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2003-11-26 01:16:41 +00:00
/* unmarshall the NDR */
status = dcerpc_pull ( & blob , mem_ctx , & pkt ) ;
2003-11-03 06:22:45 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2004-07-09 12:26:34 +00:00
if ( ( pkt . ptype ! = DCERPC_PKT_BIND_ACK ) | |
2003-11-23 06:28:12 +00:00
pkt . u . bind_ack . num_results = = 0 | |
pkt . u . bind_ack . ctx_list [ 0 ] . result ! = 0 ) {
2003-11-03 06:22:45 +00:00
status = NT_STATUS_UNSUCCESSFUL ;
}
2004-07-09 12:26:34 +00:00
if ( pkt . ptype = = DCERPC_PKT_BIND_ACK ) {
2003-11-27 04:02:15 +00:00
p - > srv_max_xmit_frag = pkt . u . bind_ack . max_xmit_frag ;
p - > srv_max_recv_frag = pkt . u . bind_ack . max_recv_frag ;
}
2003-11-03 06:22:45 +00:00
2003-11-26 01:16:41 +00:00
/* the bind_ack might contain a reply set of credentials */
2004-06-07 12:30:22 +00:00
if ( p - > security_state . auth_info & & pkt . u . bind_ack . auth_info . length ) {
2003-11-26 01:16:41 +00:00
status = ndr_pull_struct_blob ( & pkt . u . bind_ack . auth_info ,
mem_ctx ,
2004-06-07 12:30:22 +00:00
p - > security_state . auth_info ,
2003-11-26 01:16:41 +00:00
( ndr_pull_flags_fn_t ) ndr_pull_dcerpc_auth ) ;
}
2003-11-03 06:22:45 +00:00
return status ;
}
2004-07-09 12:26:34 +00:00
/*
perform a alter context using the given syntax
the auth_info structure is updated with the reply authentication info
on success
*/
NTSTATUS dcerpc_alter ( struct dcerpc_pipe * p ,
TALLOC_CTX * mem_ctx )
{
struct dcerpc_packet pkt ;
NTSTATUS status ;
DATA_BLOB blob ;
init_dcerpc_hdr ( p , & pkt ) ;
pkt . ptype = DCERPC_PKT_ALTER ;
pkt . pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST ;
pkt . call_id = p - > call_id ;
pkt . auth_length = 0 ;
pkt . u . alter . max_xmit_frag = 0x2000 ;
pkt . u . alter . max_recv_frag = 0x2000 ;
pkt . u . alter . assoc_group_id = 0 ;
pkt . u . alter . num_contexts = 1 ;
pkt . u . alter . ctx_list = talloc ( mem_ctx , sizeof ( pkt . u . alter . ctx_list [ 0 ] ) ) ;
if ( ! pkt . u . alter . ctx_list ) {
return NT_STATUS_NO_MEMORY ;
}
pkt . u . alter . ctx_list [ 0 ] . context_id = 0 ;
pkt . u . alter . ctx_list [ 0 ] . num_transfer_syntaxes = 1 ;
pkt . u . alter . ctx_list [ 0 ] . abstract_syntax = p - > syntax ;
pkt . u . alter . ctx_list [ 0 ] . transfer_syntaxes = & p - > transfer_syntax ;
pkt . u . alter . auth_info = data_blob ( NULL , 0 ) ;
/* construct the NDR form of the packet */
status = dcerpc_push_auth ( & blob , mem_ctx , & pkt , p - > security_state . auth_info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/* send it on its way */
status = p - > transport . full_request ( p , mem_ctx , & blob , & blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/* unmarshall the NDR */
status = dcerpc_pull ( & blob , mem_ctx , & pkt ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
if ( ( pkt . ptype ! = DCERPC_PKT_ALTER_ACK ) | |
pkt . u . alter_ack . num_results = = 0 | |
pkt . u . alter_ack . ctx_list [ 0 ] . result ! = 0 ) {
status = NT_STATUS_UNSUCCESSFUL ;
}
/* the bind_ack might contain a reply set of credentials */
if ( p - > security_state . auth_info & & pkt . u . alter_ack . auth_info . length ) {
status = ndr_pull_struct_blob ( & pkt . u . alter_ack . auth_info ,
mem_ctx ,
p - > security_state . auth_info ,
( ndr_pull_flags_fn_t ) ndr_pull_dcerpc_auth ) ;
}
return status ;
}
2003-11-26 01:16:41 +00:00
/*
perform a continued bind ( and auth3 )
*/
NTSTATUS dcerpc_auth3 ( struct dcerpc_pipe * p ,
TALLOC_CTX * mem_ctx )
{
struct dcerpc_packet pkt ;
NTSTATUS status ;
DATA_BLOB blob ;
2003-12-16 09:02:58 +00:00
init_dcerpc_hdr ( p , & pkt ) ;
2003-11-26 01:16:41 +00:00
pkt . ptype = DCERPC_PKT_AUTH3 ;
pkt . pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST ;
pkt . call_id = p - > call_id + + ;
pkt . auth_length = 0 ;
pkt . u . auth . _pad = 0 ;
pkt . u . auth . auth_info = data_blob ( NULL , 0 ) ;
/* construct the NDR form of the packet */
2004-06-07 12:30:22 +00:00
status = dcerpc_push_auth ( & blob , mem_ctx , & pkt , p - > security_state . auth_info ) ;
2003-11-26 01:16:41 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/* send it on its way */
status = p - > transport . initial_request ( p , mem_ctx , & blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return status ;
}
/* perform a dcerpc bind, using the uuid as the key */
2003-11-18 05:01:10 +00:00
NTSTATUS dcerpc_bind_byuuid ( struct dcerpc_pipe * p ,
2003-11-26 01:16:41 +00:00
TALLOC_CTX * mem_ctx ,
2004-06-01 10:12:52 +00:00
const char * uuid , uint_t version )
2003-11-03 06:22:45 +00:00
{
2003-11-18 05:01:10 +00:00
struct dcerpc_syntax_id syntax ;
struct dcerpc_syntax_id transfer_syntax ;
2003-11-23 06:28:12 +00:00
NTSTATUS status ;
2003-11-03 06:22:45 +00:00
2003-11-24 03:21:49 +00:00
status = GUID_from_string ( uuid , & syntax . uuid ) ;
2003-11-23 06:28:12 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 2 , ( " Invalid uuid string in dcerpc_bind_byuuid \n " ) ) ;
return status ;
}
2003-12-16 09:02:58 +00:00
syntax . if_version = version ;
2003-11-18 05:01:10 +00:00
2003-11-26 03:43:04 +00:00
status = GUID_from_string ( NDR_GUID , & transfer_syntax . uuid ) ;
2003-11-23 06:28:12 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2003-12-16 09:02:58 +00:00
transfer_syntax . if_version = NDR_GUID_VERSION ;
2003-11-03 06:22:45 +00:00
2003-11-26 01:16:41 +00:00
return dcerpc_bind ( p , mem_ctx , & syntax , & transfer_syntax ) ;
2003-11-03 06:22:45 +00:00
}
2003-11-03 06:30:33 +00:00
/*
perform a full request / response pair on a dcerpc pipe
*/
2003-11-04 09:10:31 +00:00
NTSTATUS dcerpc_request ( struct dcerpc_pipe * p ,
2004-05-25 17:24:24 +00:00
uint16_t opnum ,
2003-11-18 05:01:10 +00:00
TALLOC_CTX * mem_ctx ,
DATA_BLOB * stub_data_in ,
DATA_BLOB * stub_data_out )
2003-11-03 06:22:45 +00:00
{
struct dcerpc_packet pkt ;
NTSTATUS status ;
2003-11-26 01:16:41 +00:00
DATA_BLOB blob , payload ;
2004-05-25 16:24:13 +00:00
uint32_t remaining , chunk_size ;
2003-11-03 06:22:45 +00:00
2004-05-20 13:29:38 +00:00
/* allow the application to tell when a fault has happened */
p - > last_fault_code = 0 ;
2003-12-16 09:02:58 +00:00
init_dcerpc_hdr ( p , & pkt ) ;
2003-11-03 06:22:45 +00:00
2003-11-04 03:38:46 +00:00
remaining = stub_data_in - > length ;
/* we can write a full max_recv_frag size, minus the dcerpc
request header size */
2003-12-14 12:21:21 +00:00
chunk_size = p - > srv_max_recv_frag - ( DCERPC_MAX_SIGN_SIZE + DCERPC_REQUEST_LENGTH ) ;
2003-11-04 03:38:46 +00:00
2003-11-23 06:28:12 +00:00
pkt . ptype = DCERPC_PKT_REQUEST ;
pkt . call_id = p - > call_id + + ;
pkt . auth_length = 0 ;
pkt . u . request . alloc_hint = remaining ;
pkt . u . request . context_id = 0 ;
pkt . u . request . opnum = opnum ;
2003-11-03 06:22:45 +00:00
2003-11-04 03:38:46 +00:00
/* we send a series of pdus without waiting for a reply until
the last pdu */
while ( remaining > chunk_size ) {
if ( remaining = = stub_data_in - > length ) {
2003-11-23 06:28:12 +00:00
pkt . pfc_flags = DCERPC_PFC_FLAG_FIRST ;
2003-11-04 03:38:46 +00:00
} else {
2003-11-23 06:28:12 +00:00
pkt . pfc_flags = 0 ;
2003-11-04 03:38:46 +00:00
}
2003-11-23 06:28:12 +00:00
pkt . u . request . stub_and_verifier . data = stub_data_in - > data +
2003-11-04 03:38:46 +00:00
( stub_data_in - > length - remaining ) ;
2003-11-23 06:28:12 +00:00
pkt . u . request . stub_and_verifier . length = chunk_size ;
2003-11-04 03:38:46 +00:00
2003-11-26 01:16:41 +00:00
status = dcerpc_push_request_sign ( p , & blob , mem_ctx , & pkt ) ;
2003-11-04 03:38:46 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2003-11-26 01:16:41 +00:00
status = p - > transport . initial_request ( p , mem_ctx , & blob ) ;
2003-11-04 03:38:46 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
remaining - = chunk_size ;
}
/* now we send a pdu with LAST_FRAG sent and get the first
part of the reply */
if ( remaining = = stub_data_in - > length ) {
2003-11-23 06:28:12 +00:00
pkt . pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST ;
2003-11-04 03:38:46 +00:00
} else {
2003-11-23 06:28:12 +00:00
pkt . pfc_flags = DCERPC_PFC_FLAG_LAST ;
2003-11-04 03:38:46 +00:00
}
2003-11-23 06:28:12 +00:00
pkt . u . request . stub_and_verifier . data = stub_data_in - > data +
2003-11-04 03:38:46 +00:00
( stub_data_in - > length - remaining ) ;
2003-11-23 06:28:12 +00:00
pkt . u . request . stub_and_verifier . length = remaining ;
2003-11-26 01:16:41 +00:00
status = dcerpc_push_request_sign ( p , & blob , mem_ctx , & pkt ) ;
2003-11-03 06:22:45 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2003-11-04 03:38:46 +00:00
/* send the pdu and get the initial response pdu */
2003-11-26 01:16:41 +00:00
status = p - > transport . full_request ( p , mem_ctx , & blob , & blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2003-11-03 06:30:33 +00:00
2003-11-26 01:16:41 +00:00
status = dcerpc_pull_request_sign ( p , & blob , mem_ctx , & pkt ) ;
2003-11-03 06:30:33 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2003-11-23 06:28:12 +00:00
if ( pkt . ptype = = DCERPC_PKT_FAULT ) {
2004-08-04 06:00:14 +00:00
DEBUG ( 5 , ( " rpc fault 0x%x \n " , pkt . u . fault . status ) ) ;
2003-11-27 04:02:15 +00:00
p - > last_fault_code = pkt . u . fault . status ;
2004-08-18 06:14:47 +00:00
return NT_STATUS_NET_WRITE_FAULT ;
2003-11-23 06:28:12 +00:00
}
if ( pkt . ptype ! = DCERPC_PKT_RESPONSE ) {
2003-11-04 02:28:08 +00:00
return NT_STATUS_UNSUCCESSFUL ;
}
2003-11-23 06:28:12 +00:00
if ( ! ( pkt . pfc_flags & DCERPC_PFC_FLAG_FIRST ) ) {
2003-11-04 02:28:08 +00:00
/* something is badly wrong! */
return NT_STATUS_UNSUCCESSFUL ;
}
2003-11-23 06:28:12 +00:00
payload = pkt . u . response . stub_and_verifier ;
2003-11-04 02:28:08 +00:00
/* continue receiving fragments */
2003-11-23 06:28:12 +00:00
while ( ! ( pkt . pfc_flags & DCERPC_PFC_FLAG_LAST ) ) {
2004-05-25 16:24:13 +00:00
uint32_t length ;
2003-11-04 02:28:08 +00:00
2003-11-26 01:16:41 +00:00
status = p - > transport . secondary_request ( p , mem_ctx , & blob ) ;
2003-11-04 02:28:08 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2003-11-26 01:16:41 +00:00
status = dcerpc_pull_request_sign ( p , & blob , mem_ctx , & pkt ) ;
2003-11-04 02:28:08 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2003-11-23 06:28:12 +00:00
if ( pkt . pfc_flags & DCERPC_PFC_FLAG_FIRST ) {
2003-11-04 02:28:08 +00:00
/* start of another packet!? */
return NT_STATUS_UNSUCCESSFUL ;
}
2003-11-27 04:02:15 +00:00
if ( pkt . ptype = = DCERPC_PKT_FAULT ) {
p - > last_fault_code = pkt . u . fault . status ;
2004-08-18 06:14:47 +00:00
return NT_STATUS_NET_WRITE_FAULT ;
2003-11-27 04:02:15 +00:00
}
2003-11-23 06:28:12 +00:00
if ( pkt . ptype ! = DCERPC_PKT_RESPONSE ) {
2003-11-04 02:28:08 +00:00
return NT_STATUS_UNSUCCESSFUL ;
}
2003-11-23 06:28:12 +00:00
length = pkt . u . response . stub_and_verifier . length ;
2003-11-04 02:28:08 +00:00
2004-08-21 01:54:46 +00:00
payload . data = talloc_realloc ( payload . data ,
2003-11-04 02:28:08 +00:00
payload . length + length ) ;
if ( ! payload . data ) {
return NT_STATUS_NO_MEMORY ;
}
memcpy ( payload . data + payload . length ,
2003-11-23 06:28:12 +00:00
pkt . u . response . stub_and_verifier . data ,
2003-11-04 02:28:08 +00:00
length ) ;
payload . length + = length ;
2003-11-03 06:30:33 +00:00
}
if ( stub_data_out ) {
2003-11-04 02:28:08 +00:00
* stub_data_out = payload ;
2003-11-03 06:30:33 +00:00
}
2003-11-03 06:22:45 +00:00
2003-12-16 11:24:28 +00:00
if ( ! ( pkt . drep [ 0 ] & DCERPC_DREP_LE ) ) {
2003-12-16 09:02:58 +00:00
p - > flags | = DCERPC_PULL_BIGENDIAN ;
} else {
p - > flags & = ~ DCERPC_PULL_BIGENDIAN ;
}
2003-11-03 06:22:45 +00:00
return status ;
}
2003-11-03 08:37:48 +00:00
2003-11-22 08:11:32 +00:00
/*
this is a paranoid NDR validator . For every packet we push onto the wire
we pull it back again , then push it again . Then we compare the raw NDR data
for that to the NDR we initially generated . If they don ' t match then we know
we must have a bug in either the pull or push side of our code
*/
static NTSTATUS dcerpc_ndr_validate_in ( TALLOC_CTX * mem_ctx ,
DATA_BLOB blob ,
size_t struct_size ,
NTSTATUS ( * ndr_push ) ( struct ndr_push * , int , void * ) ,
NTSTATUS ( * ndr_pull ) ( struct ndr_pull * , int , void * ) )
{
void * st ;
struct ndr_pull * pull ;
struct ndr_push * push ;
NTSTATUS status ;
DATA_BLOB blob2 ;
st = talloc ( mem_ctx , struct_size ) ;
if ( ! st ) {
return NT_STATUS_NO_MEMORY ;
}
pull = ndr_pull_init_blob ( & blob , mem_ctx ) ;
if ( ! pull ) {
return NT_STATUS_NO_MEMORY ;
}
status = ndr_pull ( pull , NDR_IN , st ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return ndr_pull_error ( pull , NDR_ERR_VALIDATE ,
2003-11-22 11:49:22 +00:00
" failed input validation pull - %s " ,
2003-11-22 08:11:32 +00:00
nt_errstr ( status ) ) ;
}
push = ndr_push_init_ctx ( mem_ctx ) ;
if ( ! push ) {
return NT_STATUS_NO_MEMORY ;
}
status = ndr_push ( push , NDR_IN , st ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return ndr_push_error ( push , NDR_ERR_VALIDATE ,
2003-11-22 11:49:22 +00:00
" failed input validation push - %s " ,
2003-11-22 08:11:32 +00:00
nt_errstr ( status ) ) ;
}
blob2 = ndr_push_blob ( push ) ;
if ( ! data_blob_equal ( & blob , & blob2 ) ) {
2003-11-22 09:32:35 +00:00
DEBUG ( 3 , ( " original: \n " ) ) ;
dump_data ( 3 , blob . data , blob . length ) ;
DEBUG ( 3 , ( " secondary: \n " ) ) ;
dump_data ( 3 , blob2 . data , blob2 . length ) ;
2003-11-22 08:11:32 +00:00
return ndr_push_error ( push , NDR_ERR_VALIDATE ,
2003-11-22 11:49:22 +00:00
" failed input validation data - %s " ,
2003-11-22 08:11:32 +00:00
nt_errstr ( status ) ) ;
}
return NT_STATUS_OK ;
}
/*
this is a paranoid NDR input validator . For every packet we pull
from the wire we push it back again then pull and push it
again . Then we compare the raw NDR data for that to the NDR we
initially generated . If they don ' t match then we know we must have a
bug in either the pull or push side of our code
*/
static NTSTATUS dcerpc_ndr_validate_out ( TALLOC_CTX * mem_ctx ,
void * struct_ptr ,
size_t struct_size ,
NTSTATUS ( * ndr_push ) ( struct ndr_push * , int , void * ) ,
NTSTATUS ( * ndr_pull ) ( struct ndr_pull * , int , void * ) )
{
void * st ;
struct ndr_pull * pull ;
struct ndr_push * push ;
NTSTATUS status ;
DATA_BLOB blob , blob2 ;
st = talloc ( mem_ctx , struct_size ) ;
if ( ! st ) {
return NT_STATUS_NO_MEMORY ;
}
memcpy ( st , struct_ptr , struct_size ) ;
push = ndr_push_init_ctx ( mem_ctx ) ;
if ( ! push ) {
return NT_STATUS_NO_MEMORY ;
}
status = ndr_push ( push , NDR_OUT , struct_ptr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return ndr_push_error ( push , NDR_ERR_VALIDATE ,
2003-11-22 11:49:22 +00:00
" failed output validation push - %s " ,
2003-11-22 08:11:32 +00:00
nt_errstr ( status ) ) ;
}
blob = ndr_push_blob ( push ) ;
pull = ndr_pull_init_blob ( & blob , mem_ctx ) ;
if ( ! pull ) {
return NT_STATUS_NO_MEMORY ;
}
pull - > flags | = LIBNDR_FLAG_REF_ALLOC ;
status = ndr_pull ( pull , NDR_OUT , st ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return ndr_pull_error ( pull , NDR_ERR_VALIDATE ,
2003-11-22 11:49:22 +00:00
" failed output validation pull - %s " ,
2003-11-22 08:11:32 +00:00
nt_errstr ( status ) ) ;
}
push = ndr_push_init_ctx ( mem_ctx ) ;
if ( ! push ) {
return NT_STATUS_NO_MEMORY ;
}
status = ndr_push ( push , NDR_OUT , st ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return ndr_push_error ( push , NDR_ERR_VALIDATE ,
2003-11-22 11:49:22 +00:00
" failed output validation push2 - %s " ,
2003-11-22 08:11:32 +00:00
nt_errstr ( status ) ) ;
}
blob2 = ndr_push_blob ( push ) ;
if ( ! data_blob_equal ( & blob , & blob2 ) ) {
2003-11-22 09:32:35 +00:00
DEBUG ( 3 , ( " original: \n " ) ) ;
dump_data ( 3 , blob . data , blob . length ) ;
DEBUG ( 3 , ( " secondary: \n " ) ) ;
dump_data ( 3 , blob2 . data , blob2 . length ) ;
2003-11-22 08:11:32 +00:00
return ndr_push_error ( push , NDR_ERR_VALIDATE ,
2003-11-22 11:49:22 +00:00
" failed output validation data - %s " ,
2003-11-22 08:11:32 +00:00
nt_errstr ( status ) ) ;
}
return NT_STATUS_OK ;
}
2003-11-03 08:37:48 +00:00
/*
2003-11-04 22:42:00 +00:00
a useful helper function for synchronous rpc requests
this can be used when you have ndr push / pull functions in the
standard format
2003-11-03 08:37:48 +00:00
*/
NTSTATUS dcerpc_ndr_request ( struct dcerpc_pipe * p ,
2004-05-25 16:24:13 +00:00
uint32_t opnum ,
2003-11-03 08:37:48 +00:00
TALLOC_CTX * mem_ctx ,
2003-11-22 08:11:32 +00:00
NTSTATUS ( * ndr_push ) ( struct ndr_push * , int , void * ) ,
NTSTATUS ( * ndr_pull ) ( struct ndr_pull * , int , void * ) ,
void * struct_ptr ,
size_t struct_size )
2003-11-03 08:37:48 +00:00
{
struct ndr_push * push ;
struct ndr_pull * pull ;
NTSTATUS status ;
DATA_BLOB request , response ;
/* setup for a ndr_push_* call */
push = ndr_push_init ( ) ;
if ( ! push ) {
talloc_destroy ( mem_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
2003-12-16 09:02:58 +00:00
if ( p - > flags & DCERPC_PUSH_BIGENDIAN ) {
push - > flags | = LIBNDR_FLAG_BIGENDIAN ;
}
2003-11-03 08:37:48 +00:00
/* push the structure into a blob */
2003-11-22 08:11:32 +00:00
status = ndr_push ( push , NDR_IN , struct_ptr ) ;
2003-11-03 08:37:48 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto failed ;
}
/* retrieve the blob */
request = ndr_push_blob ( push ) ;
2003-11-22 08:11:32 +00:00
if ( p - > flags & DCERPC_DEBUG_VALIDATE_IN ) {
status = dcerpc_ndr_validate_in ( mem_ctx , request , struct_size ,
ndr_push , ndr_pull ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto failed ;
}
}
2003-11-20 01:28:33 +00:00
DEBUG ( 10 , ( " rpc request data: \n " ) ) ;
2003-11-14 07:20:46 +00:00
dump_data ( 10 , request . data , request . length ) ;
2003-11-03 08:37:48 +00:00
/* make the actual dcerpc request */
2003-11-04 09:10:31 +00:00
status = dcerpc_request ( p , opnum , mem_ctx , & request , & response ) ;
2003-11-03 08:37:48 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto failed ;
}
/* prepare for ndr_pull_* */
pull = ndr_pull_init_blob ( & response , mem_ctx ) ;
if ( ! pull ) {
goto failed ;
}
2003-12-16 09:02:58 +00:00
if ( p - > flags & DCERPC_PULL_BIGENDIAN ) {
pull - > flags | = LIBNDR_FLAG_BIGENDIAN ;
}
2003-11-20 01:28:33 +00:00
DEBUG ( 10 , ( " rpc reply data: \n " ) ) ;
2003-11-13 09:26:53 +00:00
dump_data ( 10 , pull - > data , pull - > data_size ) ;
2003-11-03 08:37:48 +00:00
/* pull the structure from the blob */
2003-11-22 08:11:32 +00:00
status = ndr_pull ( pull , NDR_OUT , struct_ptr ) ;
2003-11-03 08:37:48 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto failed ;
}
2003-11-26 01:16:41 +00:00
/* possibly check the packet signature */
2003-11-22 08:11:32 +00:00
if ( p - > flags & DCERPC_DEBUG_VALIDATE_OUT ) {
status = dcerpc_ndr_validate_out ( mem_ctx , struct_ptr , struct_size ,
ndr_push , ndr_pull ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto failed ;
}
}
2003-11-09 11:01:39 +00:00
if ( pull - > offset ! = pull - > data_size ) {
2004-07-15 05:11:27 +00:00
DEBUG ( 0 , ( " Warning! ignoring %d unread bytes in rpc packet! \n " ,
pull - > data_size - pull - > offset ) ) ;
/* we used return NT_STATUS_INFO_LENGTH_MISMATCH here,
but it turns out that early versions of NT
( specifically NT3 .1 ) add junk onto the end of rpc
packets , so if we want to interoperate at all with
those versions then we need to ignore this error */
2003-11-09 11:01:39 +00:00
}
2003-11-03 08:37:48 +00:00
failed :
ndr_push_free ( push ) ;
return status ;
}
2003-11-11 04:04:36 +00:00
2003-11-17 03:38:13 +00:00
/*
a useful function for retrieving the server name we connected to
*/
const char * dcerpc_server_name ( struct dcerpc_pipe * p )
{
2003-11-24 11:45:33 +00:00
if ( ! p - > transport . peer_name ) {
return " " ;
}
return p - > transport . peer_name ( p ) ;
2003-11-17 03:38:13 +00:00
}
2004-08-25 02:25:20 +00:00
/*
a useful function to get the auth_level
*/
uint32 dcerpc_auth_level ( struct dcerpc_pipe * p )
{
uint8_t auth_level ;
if ( p - > flags & DCERPC_SEAL ) {
auth_level = DCERPC_AUTH_LEVEL_PRIVACY ;
} else if ( p - > flags & DCERPC_SIGN ) {
auth_level = DCERPC_AUTH_LEVEL_INTEGRITY ;
} else {
auth_level = DCERPC_AUTH_LEVEL_NONE ;
}
return auth_level ;
}