1998-11-12 19:07:00 +03:00
/*
2002-01-30 09:08:46 +03:00
* Unix SMB / CIFS implementation .
1998-11-12 19:07:00 +03:00
* RPC Pipe client / server routines
2010-02-19 03:12:04 +03:00
* Almost completely rewritten by ( C ) Jeremy Allison 2005 - 2010
1998-11-12 19:07:00 +03: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
2007-07-09 23:25:36 +04:00
* the Free Software Foundation ; either version 3 of the License , or
1998-11-12 19:07:00 +03: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 09:23:25 +04:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
1998-11-12 19:07:00 +03:00
*/
/* this module apparently provides an implementation of DCE/RPC over a
* named pipe ( IPC $ connection using SMBtrans ) . details of DCE / RPC
* documentation are available ( in on - line form ) from the X - Open group .
*
* this module should provide a level of abstraction between SMB
* and DCE / RPC , while minimising the amount of mallocs , unnecessary
* data copies , and network traffic .
*
*/
# include "includes.h"
2010-06-04 00:01:46 +04:00
# include "srv_pipe_internal.h"
2009-09-08 17:31:01 +04:00
# include "../librpc/gen_ndr/ndr_schannel.h"
2010-08-27 23:23:20 +04:00
# include "../librpc/gen_ndr/ndr_krb5pac.h"
2009-09-16 02:26:17 +04:00
# include "../libcli/auth/schannel.h"
2009-09-17 02:21:01 +04:00
# include "../libcli/auth/spnego.h"
2010-09-02 01:09:52 +04:00
# include "dcesrv_ntlmssp.h"
2010-07-17 23:22:26 +04:00
# include "rpc_server.h"
2010-08-18 20:26:17 +04:00
# include "rpc_dce.h"
2010-09-01 19:58:33 +04:00
# include "librpc/crypto/gse.h"
1998-11-12 19:07:00 +03:00
2002-07-15 14:35:28 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_RPC_SRV
2010-07-16 00:54:14 +04:00
/**
* Dump everything from the start of the end up of the provided data
* into a file , but only at debug level > = 50
* */
static void dump_pdu_region ( const char * name , int v ,
DATA_BLOB * data , size_t start , size_t end )
{
int fd , i ;
char * fname = NULL ;
ssize_t sz ;
if ( DEBUGLEVEL < 50 ) return ;
if ( start > data - > length | | end > data - > length | | start > end ) return ;
for ( i = 1 ; i < 100 ; i + + ) {
if ( v ! = - 1 ) {
fname = talloc_asprintf ( talloc_tos ( ) ,
" /tmp/%s_%d.%d.prs " ,
name , v , i ) ;
} else {
fname = talloc_asprintf ( talloc_tos ( ) ,
" /tmp/%s_%d.prs " ,
name , i ) ;
}
if ( ! fname ) {
return ;
}
fd = open ( fname , O_WRONLY | O_CREAT | O_EXCL , 0644 ) ;
if ( fd ! = - 1 | | errno ! = EEXIST ) break ;
}
if ( fd ! = - 1 ) {
sz = write ( fd , data - > data + start , end - start ) ;
i = close ( fd ) ;
if ( ( sz ! = end - start ) | | ( i ! = 0 ) ) {
DEBUG ( 0 , ( " Error writing/closing %s: %ld!=%ld %d \n " ,
fname , ( unsigned long ) sz ,
( unsigned long ) end - start , i ) ) ;
} else {
DEBUG ( 0 , ( " created %s \n " , fname ) ) ;
}
}
TALLOC_FREE ( fname ) ;
}
2005-09-30 21:13:37 +04:00
static void free_pipe_ntlmssp_auth_data ( struct pipe_auth_data * auth )
2000-03-10 00:45:16 +03:00
{
2010-07-17 03:44:22 +04:00
TALLOC_FREE ( auth - > a_u . auth_ntlmssp_state ) ;
2000-03-10 00:45:16 +03:00
}
2010-07-18 00:01:07 +04:00
static void free_pipe_schannel_auth_data ( struct pipe_auth_data * auth )
{
TALLOC_FREE ( auth - > a_u . schannel_auth ) ;
}
2010-08-27 23:23:20 +04:00
static void free_pipe_gssapi_auth_data ( struct pipe_auth_data * auth )
{
TALLOC_FREE ( auth - > a_u . gssapi_state ) ;
}
2010-07-18 00:34:33 +04:00
static void free_pipe_auth_data ( struct pipe_auth_data * auth )
{
if ( auth - > auth_data_free_func ) {
( * auth - > auth_data_free_func ) ( auth ) ;
auth - > auth_data_free_func = NULL ;
}
}
2006-06-06 00:38:21 +04:00
static DATA_BLOB generic_session_key ( void )
{
return data_blob ( " SystemLibraryDTC " , 16 ) ;
}
2000-03-10 00:45:16 +03:00
/*******************************************************************
2010-07-14 07:56:01 +04:00
Generate the next PDU to be returned from the data .
2005-09-30 21:13:37 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-03-10 00:45:16 +03:00
2010-07-30 22:01:01 +04:00
static NTSTATUS create_next_packet ( TALLOC_CTX * mem_ctx ,
struct pipe_auth_data * auth ,
uint32_t call_id ,
DATA_BLOB * rdata ,
size_t data_sent_length ,
DATA_BLOB * frag ,
size_t * pdu_size )
2003-02-14 03:48:28 +03:00
{
2010-07-13 19:53:41 +04:00
union dcerpc_payload u ;
2010-07-14 07:56:01 +04:00
uint8_t pfc_flags ;
2010-07-30 22:01:01 +04:00
size_t data_left ;
size_t data_to_send ;
size_t frag_len ;
2010-07-14 07:56:01 +04:00
size_t pad_len = 0 ;
2010-07-30 20:19:20 +04:00
size_t auth_len = 0 ;
2010-07-14 07:56:01 +04:00
NTSTATUS status ;
2000-03-10 00:45:16 +03:00
2010-07-13 19:53:41 +04:00
ZERO_STRUCT ( u . response ) ;
2000-03-10 00:45:16 +03:00
2010-07-14 07:56:01 +04:00
/* Set up rpc packet pfc flags. */
2010-07-30 20:19:20 +04:00
if ( data_sent_length = = 0 ) {
2010-07-14 07:56:01 +04:00
pfc_flags = DCERPC_PFC_FLAG_FIRST ;
2005-09-30 21:13:37 +04:00
} else {
2010-07-14 07:56:01 +04:00
pfc_flags = 0 ;
2000-03-10 00:45:16 +03:00
}
2010-07-14 07:56:01 +04:00
/* Work out how much we can fit in a single PDU. */
2010-07-30 22:01:01 +04:00
data_left = rdata - > length - data_sent_length ;
2005-09-30 21:13:37 +04:00
2010-07-14 07:56:01 +04:00
/* Ensure there really is data left to send. */
2010-07-30 22:01:01 +04:00
if ( ! data_left ) {
2010-07-14 07:56:01 +04:00
DEBUG ( 0 , ( " No data left to send ! \n " ) ) ;
2010-07-30 22:01:01 +04:00
return NT_STATUS_BUFFER_TOO_SMALL ;
2010-07-14 07:56:01 +04:00
}
2005-09-30 21:13:37 +04:00
2010-07-30 22:01:01 +04:00
status = dcerpc_guess_sizes ( auth ,
DCERPC_RESPONSE_LENGTH ,
data_left ,
RPC_MAX_PDU_FRAG_LEN ,
SERVER_NDR_PADDING_SIZE ,
& data_to_send , & frag_len ,
& auth_len , & pad_len ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2010-07-14 07:56:01 +04:00
}
2005-09-30 21:13:37 +04:00
2010-07-14 07:56:01 +04:00
/* Set up the alloc hint. This should be the data left to send. */
2010-07-30 22:01:01 +04:00
u . response . alloc_hint = data_left ;
2005-09-30 21:13:37 +04:00
2010-07-14 07:56:01 +04:00
/* Work out if this PDU will be the last. */
2010-07-30 22:01:01 +04:00
if ( data_sent_length + data_to_send > = rdata - > length ) {
2010-07-14 07:56:01 +04:00
pfc_flags | = DCERPC_PFC_FLAG_LAST ;
2005-09-30 21:13:37 +04:00
}
2010-07-14 07:56:01 +04:00
/* Prepare data to be NDR encoded. */
2010-07-13 19:53:41 +04:00
u . response . stub_and_verifier =
2010-07-30 22:01:01 +04:00
data_blob_const ( rdata - > data + data_sent_length , data_to_send ) ;
2010-07-13 19:53:41 +04:00
2010-07-14 02:01:16 +04:00
/* Store the packet in the data stream. */
2010-07-30 20:19:20 +04:00
status = dcerpc_push_ncacn_packet ( mem_ctx , DCERPC_PKT_RESPONSE ,
pfc_flags , auth_len , call_id ,
& u , frag ) ;
2010-07-09 23:46:43 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-07-14 07:56:01 +04:00
DEBUG ( 0 , ( " Failed to marshall RPC Packet. \n " ) ) ;
2010-07-30 22:01:01 +04:00
return status ;
2000-03-10 00:45:16 +03:00
}
2010-07-30 20:19:20 +04:00
if ( auth_len ) {
2010-07-14 07:56:01 +04:00
/* Set the proper length on the pdu, including padding.
* Only needed if an auth trailer will be appended . */
2010-07-30 20:19:20 +04:00
dcerpc_set_frag_length ( frag , frag - > length
2010-07-14 07:56:01 +04:00
+ pad_len
+ DCERPC_AUTH_TRAILER_LENGTH
2010-07-30 20:19:20 +04:00
+ auth_len ) ;
2010-07-14 07:56:01 +04:00
}
2000-03-10 00:45:16 +03:00
2010-07-30 20:19:20 +04:00
if ( auth_len ) {
status = dcerpc_add_auth_footer ( auth , pad_len , frag ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
data_blob_free ( frag ) ;
2010-07-30 22:01:01 +04:00
return status ;
2010-07-30 20:19:20 +04:00
}
}
2010-07-30 22:01:01 +04:00
* pdu_size = data_to_send ;
return NT_STATUS_OK ;
2005-09-30 21:13:37 +04:00
}
/*******************************************************************
Generate the next PDU to be returned from the data in p - > rdata .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-28 12:16:34 +04:00
bool create_next_pdu ( struct pipes_struct * p )
2005-09-30 21:13:37 +04:00
{
2010-08-03 17:55:20 +04:00
size_t pdu_size = 0 ;
2010-07-30 22:01:01 +04:00
NTSTATUS status ;
2009-01-06 13:32:07 +03:00
2010-07-14 07:56:01 +04:00
/*
* If we ' re in the fault state , keep returning fault PDU ' s until
* the pipe gets closed . JRA .
*/
if ( p - > fault_state ) {
setup_fault_pdu ( p , NT_STATUS ( DCERPC_FAULT_OP_RNG_ERROR ) ) ;
return true ;
}
2010-07-30 22:01:01 +04:00
status = create_next_packet ( p - > mem_ctx , & p - > auth ,
p - > call_id , & p - > out_data . rdata ,
p - > out_data . data_sent_length ,
& p - > out_data . frag , & pdu_size ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Failed to create packet with error %s, "
" (auth level %u / type %u) \n " ,
nt_errstr ( status ) ,
2010-07-30 20:19:20 +04:00
( unsigned int ) p - > auth . auth_level ,
( unsigned int ) p - > auth . auth_type ) ) ;
2010-07-20 00:16:40 +04:00
return false ;
}
2010-07-30 20:19:20 +04:00
/* Setup the counts for this PDU. */
p - > out_data . data_sent_length + = pdu_size ;
p - > out_data . current_pdu_sent = 0 ;
2010-07-20 00:16:40 +04:00
return true ;
2005-09-30 21:13:37 +04:00
}
/*******************************************************************
Process an NTLMSSP authentication response .
If this function succeeds , the user has been authenticated
and their domain , name and calling workstation stored in
the pipe struct .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-09-02 01:09:52 +04:00
static bool pipe_ntlmssp_verify_final ( TALLOC_CTX * mem_ctx ,
struct auth_ntlmssp_state * ntlmssp_ctx ,
enum dcerpc_AuthLevel auth_level ,
struct client_address * client_id ,
struct ndr_syntax_id * syntax ,
struct auth_serversupplied_info * * server_info )
2005-09-30 21:13:37 +04:00
{
2010-09-02 01:09:52 +04:00
DATA_BLOB session_key ;
2005-09-30 21:13:37 +04:00
NTSTATUS status ;
2008-06-24 16:33:31 +04:00
bool ret ;
2005-09-30 21:13:37 +04:00
2010-09-02 01:09:52 +04:00
DEBUG ( 5 , ( __location__ " : pipe %s checking user details \n " ,
get_pipe_name_from_syntax ( talloc_tos ( ) , syntax ) ) ) ;
2000-03-10 00:45:16 +03:00
2006-04-18 22:00:57 +04:00
/* Finally - if the pipe negotiated integrity (sign) or privacy (seal)
ensure the underlying NTLMSSP flags are also set . If not we should
refuse the bind . */
2010-09-02 01:09:52 +04:00
status = ntlmssp_server_check_flags ( ntlmssp_ctx ,
( auth_level = =
DCERPC_AUTH_LEVEL_INTEGRITY ) ,
( auth_level = =
DCERPC_AUTH_LEVEL_PRIVACY ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( __location__ " : Client failed to negotatie proper "
" security for pipe %s \n " ,
get_pipe_name_from_syntax ( talloc_tos ( ) , syntax ) ) ) ;
return false ;
2006-04-18 22:00:57 +04:00
}
2007-10-11 00:34:30 +04:00
2010-09-02 01:09:52 +04:00
TALLOC_FREE ( * server_info ) ;
2006-07-11 22:01:26 +04:00
2010-09-02 01:09:52 +04:00
status = ntlmssp_server_get_user_info ( ntlmssp_ctx ,
mem_ctx , server_info ) ;
2010-07-12 08:26:34 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-09-02 01:09:52 +04:00
DEBUG ( 0 , ( __location__ " : failed to obtain the server info "
" for authenticated user: %s \n " , nt_errstr ( status ) ) ) ;
2008-06-24 16:18:55 +04:00
return false ;
}
2010-09-02 01:09:52 +04:00
if ( ( * server_info ) - > ptok = = NULL ) {
DEBUG ( 1 , ( " Auth module failed to provide nt_user_token \n " ) ) ;
return false ;
2010-05-25 09:34:06 +04:00
}
2008-06-24 16:33:31 +04:00
/*
* We ' re an authenticated bind over smb , so the session key needs to
* be set to " SystemLibraryDTC " . Weird , but this is what Windows
* does . See the RPC - SAMBA3SESSIONKEY .
*/
session_key = generic_session_key ( ) ;
if ( session_key . data = = NULL ) {
2010-09-02 01:09:52 +04:00
return false ;
2008-06-24 16:33:31 +04:00
}
2010-09-02 01:09:52 +04:00
ret = server_info_set_session_key ( ( * server_info ) , session_key ) ;
2008-06-24 16:33:31 +04:00
data_blob_free ( & session_key ) ;
2010-09-02 01:09:52 +04:00
if ( ! ret ) {
DEBUG ( 0 , ( " Failed to set session key! \n " ) ) ;
return false ;
}
2008-06-24 16:18:55 +04:00
2010-09-02 01:09:52 +04:00
return true ;
2005-09-30 21:13:37 +04:00
}
2010-08-27 23:23:20 +04:00
static NTSTATUS pipe_gssapi_auth_bind_next ( struct pipes_struct * p ,
TALLOC_CTX * mem_ctx ,
struct dcerpc_auth * pauth_info ,
DATA_BLOB * response ) ;
2010-09-02 01:09:52 +04:00
static NTSTATUS finalize_gssapi_bind ( TALLOC_CTX * mem_ctx ,
struct gse_context * gse_ctx ,
struct client_address * client_id ,
struct auth_serversupplied_info * * sinfo ) ;
2010-08-27 23:23:20 +04:00
2005-09-30 21:13:37 +04:00
/*******************************************************************
2010-08-27 23:23:20 +04:00
This is the " stage3 " response after a bind request and reply .
2005-09-30 21:13:37 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-28 12:16:34 +04:00
bool api_pipe_bind_auth3 ( struct pipes_struct * p , struct ncacn_packet * pkt )
2005-09-30 21:13:37 +04:00
{
2010-07-09 02:38:25 +04:00
struct dcerpc_auth auth_info ;
2010-08-27 23:23:20 +04:00
DATA_BLOB response = data_blob_null ;
2010-07-09 02:38:25 +04:00
NTSTATUS status ;
2005-09-30 21:13:37 +04:00
2010-07-14 21:56:13 +04:00
DEBUG ( 5 , ( " api_pipe_bind_auth3: decode request. %d \n " , __LINE__ ) ) ;
2005-09-30 21:13:37 +04:00
2010-07-14 21:56:13 +04:00
if ( pkt - > auth_length = = 0 ) {
DEBUG ( 0 , ( " No auth field sent for bind request! \n " ) ) ;
2005-09-30 21:13:37 +04:00
goto err ;
}
2010-02-18 02:27:59 +03:00
/* Ensure there's enough data for an authenticated request. */
2010-07-14 21:56:13 +04:00
if ( pkt - > frag_length < RPC_HEADER_LEN
+ DCERPC_AUTH_TRAILER_LENGTH
+ pkt - > auth_length ) {
2010-02-18 02:27:59 +03:00
DEBUG ( 0 , ( " api_pipe_ntlmssp_auth_process: auth_len "
" %u is too large. \n " ,
2010-07-14 21:56:13 +04:00
( unsigned int ) pkt - > auth_length ) ) ;
2010-02-18 02:27:59 +03:00
goto err ;
}
2005-09-30 21:13:37 +04:00
/*
* Decode the authentication verifier response .
*/
2010-07-10 03:34:34 +04:00
status = dcerpc_pull_dcerpc_auth ( pkt ,
& pkt - > u . auth3 . auth_info ,
2010-07-16 23:15:48 +04:00
& auth_info , p - > endian ) ;
2010-07-09 02:38:25 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Failed to unmarshall dcerpc_auth. \n " ) ) ;
2005-09-30 21:13:37 +04:00
goto err ;
}
2010-02-18 02:27:59 +03:00
/* We must NEVER look at auth_info->auth_pad_len here,
* as old Samba client code gets it wrong and sends it
* as zero . JRA .
*/
2010-08-27 23:23:20 +04:00
switch ( auth_info . auth_type ) {
case DCERPC_AUTH_TYPE_NTLMSSP :
2010-09-02 01:09:52 +04:00
status = ntlmssp_server_step ( p - > auth . a_u . auth_ntlmssp_state ,
pkt , & auth_info . credentials ,
& response ) ;
2010-08-27 23:23:20 +04:00
break ;
case DCERPC_AUTH_TYPE_KRB5 :
status = pipe_gssapi_auth_bind_next ( p , pkt ,
& auth_info , & response ) ;
2010-09-02 01:09:52 +04:00
break ;
default :
DEBUG ( 0 , ( __location__ " : incorrect auth type (%u). \n " ,
( unsigned int ) auth_info . auth_type ) ) ;
return false ;
}
if ( NT_STATUS_EQUAL ( status ,
NT_STATUS_MORE_PROCESSING_REQUIRED ) | |
response . length ) {
DEBUG ( 0 , ( __location__ " : This was supposed to be the final "
" leg, but crypto machinery claims a response is "
" needed, aborting auth! \n " ) ) ;
data_blob_free ( & response ) ;
goto err ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Auth failed (%s) \n " , nt_errstr ( status ) ) ) ;
goto err ;
}
/* Now verify auth was indeed successful and extract server info */
switch ( auth_info . auth_type ) {
case DCERPC_AUTH_TYPE_NTLMSSP :
if ( ! pipe_ntlmssp_verify_final ( p ,
p - > auth . a_u . auth_ntlmssp_state ,
p - > auth . auth_level ,
p - > client_id , & p - > syntax ,
& p - > server_info ) ) {
2010-08-27 23:23:20 +04:00
goto err ;
}
2010-09-02 01:09:52 +04:00
break ;
case DCERPC_AUTH_TYPE_KRB5 :
status = finalize_gssapi_bind ( p , p - > auth . a_u . gssapi_state ,
p - > client_id , & p - > server_info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " gssapi bind failed with: %s " ,
nt_errstr ( status ) ) ) ;
2010-08-27 23:23:20 +04:00
goto err ;
}
break ;
default :
DEBUG ( 0 , ( __location__ " : incorrect auth type (%u). \n " ,
( unsigned int ) auth_info . auth_type ) ) ;
return false ;
2005-09-30 21:13:37 +04:00
}
2000-03-10 00:45:16 +03:00
/*
* The following call actually checks the challenge / response data .
* for correctness against the given DOMAIN \ user name .
*/
2009-01-06 13:32:07 +03:00
2010-08-27 23:23:20 +04:00
p - > pipe_bound = true ;
return true ;
2005-09-30 21:13:37 +04:00
2010-08-27 23:23:20 +04:00
err :
2005-09-30 21:13:37 +04:00
2010-07-18 00:34:33 +04:00
free_pipe_auth_data ( & p - > auth ) ;
2010-08-27 23:23:20 +04:00
return false ;
1999-04-27 14:43:32 +04:00
}
2010-07-28 12:16:34 +04:00
static bool pipe_init_outgoing_data ( struct pipes_struct * p ) ;
2010-07-20 21:56:25 +04:00
2000-03-10 00:45:16 +03:00
/*******************************************************************
Marshall a bind_nak pdu .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-28 12:16:34 +04:00
static bool setup_bind_nak ( struct pipes_struct * p , struct ncacn_packet * pkt )
1998-11-12 19:07:00 +03:00
{
2009-03-21 02:11:15 +03:00
NTSTATUS status ;
union dcerpc_payload u ;
2000-03-10 00:45:16 +03:00
/* Free any memory in the current return data buffer. */
2010-07-20 21:56:25 +04:00
pipe_init_outgoing_data ( p ) ;
2000-03-10 00:45:16 +03:00
/*
* Initialize a bind_nak header .
*/
2009-03-21 02:11:15 +03:00
ZERO_STRUCT ( u ) ;
2000-03-10 00:45:16 +03:00
2009-03-21 02:11:15 +03:00
u . bind_nak . reject_reason = 0 ;
2000-03-10 00:45:16 +03:00
2010-07-14 02:01:16 +04:00
/*
* Marshall directly into the outgoing PDU space . We
* must do this as we need to set to the bind response
* header and are never sending more than one PDU here .
*/
2009-03-21 02:11:15 +03:00
status = dcerpc_push_ncacn_packet ( p - > mem_ctx ,
DCERPC_PKT_BIND_NAK ,
2010-07-09 03:17:13 +04:00
DCERPC_PFC_FLAG_FIRST |
DCERPC_PFC_FLAG_LAST ,
2009-03-21 02:11:15 +03:00
0 ,
2010-07-11 18:37:07 +04:00
pkt - > call_id ,
2010-07-11 20:18:13 +04:00
& u ,
2010-07-14 02:01:16 +04:00
& p - > out_data . frag ) ;
2009-03-21 02:11:15 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2005-08-05 04:25:52 +04:00
return False ;
2000-07-27 04:47:19 +04:00
}
1998-11-12 19:07:00 +03:00
2000-03-10 00:45:16 +03:00
p - > out_data . data_sent_length = 0 ;
p - > out_data . current_pdu_sent = 0 ;
1998-11-12 19:07:00 +03:00
2010-07-18 00:34:33 +04:00
free_pipe_auth_data ( & p - > auth ) ;
2009-09-14 22:39:54 +04:00
p - > auth . auth_level = DCERPC_AUTH_LEVEL_NONE ;
2010-07-20 21:26:36 +04:00
p - > auth . auth_type = DCERPC_AUTH_TYPE_NONE ;
p - > auth . spnego_type = PIPE_AUTH_TYPE_SPNEGO_NONE ;
2000-03-10 00:45:16 +03:00
p - > pipe_bound = False ;
return True ;
delineation between smb and msrpc more marked. smbd now constructs
pdus, and then feeds them over either a "local" function call or a "remote"
function call to an msrpc service. the "remote" msrpc daemon, on the
other side of a unix socket, then calls the same "local" function that
smbd would, if the msrpc service were being run from inside smbd.
this allows a transition from local msrpc services (inside the same smbd
process) to remote (over a unix socket).
removed reference to pipes_struct in msrpc services. all msrpc processing
functions take rpcsrv_struct which is a structure containing state info
for the msrpc functions to decode and create pdus.
created become_vuser() which does everything not related to connection_struct
that become_user() does.
removed, as best i could, connection_struct dependencies from the nt spoolss
printing code.
todo: remove dcinfo from rpcsrv_struct because this stores NETLOGON-specific
info on a per-connection basis, and if the connection dies then so does
the info, and that's a fairly serious problem.
had to put pretty much everything that is in user_struct into parse_creds.c
to feed unix user info over to the msrpc daemons. why? because it's
expensive to do unix password/group database lookups, and it's definitely
expensive to do nt user profile lookups, not to mention pretty difficult
and if you did either of these it would introduce a complication /
unnecessary interdependency. so, send uid/gid/num_groups/gid_t* +
SID+num_rids+domain_group_rids* + unix username + nt username + nt domain
+ user session key etc. this is the MINIMUM info identified so far that's
actually implemented. missing bits include the called and calling
netbios names etc. (basically, anything that can be loaded into
standard_sub() and standard_sub_basic()...)
(This used to be commit aa3c659a8dba0437c17c60055a6ed30fdfecdb6d)
1999-12-12 04:25:49 +03:00
}
2000-03-10 00:45:16 +03:00
/*******************************************************************
Marshall a fault pdu .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-28 12:16:34 +04:00
bool setup_fault_pdu ( struct pipes_struct * p , NTSTATUS fault_status )
2000-03-10 00:45:16 +03:00
{
2009-03-23 13:05:21 +03:00
NTSTATUS status ;
union dcerpc_payload u ;
2000-03-10 00:45:16 +03:00
/* Free any memory in the current return data buffer. */
2010-07-20 21:56:25 +04:00
pipe_init_outgoing_data ( p ) ;
2000-03-10 00:45:16 +03:00
/*
* Initialize a fault header .
*/
2009-03-23 13:05:21 +03:00
ZERO_STRUCT ( u ) ;
2000-03-10 00:45:16 +03:00
2009-03-23 13:05:21 +03:00
u . fault . status = NT_STATUS_V ( fault_status ) ;
u . fault . _pad = data_blob_talloc_zero ( p - > mem_ctx , 4 ) ;
2000-03-10 00:45:16 +03:00
2010-07-14 02:01:16 +04:00
/*
* Marshall directly into the outgoing PDU space . We
* must do this as we need to set to the bind response
* header and are never sending more than one PDU here .
*/
2009-03-23 13:05:21 +03:00
status = dcerpc_push_ncacn_packet ( p - > mem_ctx ,
DCERPC_PKT_FAULT ,
2010-07-09 03:17:13 +04:00
DCERPC_PFC_FLAG_FIRST |
DCERPC_PFC_FLAG_LAST |
DCERPC_PFC_FLAG_DID_NOT_EXECUTE ,
2009-03-23 13:05:21 +03:00
0 ,
2010-07-10 03:34:34 +04:00
p - > call_id ,
2010-07-11 20:18:13 +04:00
& u ,
2010-07-14 02:01:16 +04:00
& p - > out_data . frag ) ;
2009-03-23 13:05:21 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2000-03-10 00:45:16 +03:00
return False ;
}
p - > out_data . data_sent_length = 0 ;
p - > out_data . current_pdu_sent = 0 ;
return True ;
}
2000-05-16 00:08:26 +04:00
/*******************************************************************
Ensure a bind request has the correct abstract & transfer interface .
Used to reject unknown binds from Win2k .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-07-05 12:13:03 +04:00
static bool check_bind_req ( struct pipes_struct * p ,
struct ndr_syntax_id * abstract ,
struct ndr_syntax_id * transfer ,
uint32 context_id )
2000-05-16 00:08:26 +04:00
{
2008-07-16 02:03:49 +04:00
struct pipe_rpc_fns * context_fns ;
2000-05-16 00:08:26 +04:00
2009-11-08 21:37:53 +03:00
DEBUG ( 3 , ( " check_bind_req for %s \n " ,
get_pipe_name_from_syntax ( talloc_tos ( ) , & p - > syntax ) ) ) ;
2002-10-04 08:10:23 +04:00
/* we have to check all now since win2k introduced a new UUID on the lsaprpc pipe */
2010-06-04 00:01:46 +04:00
if ( rpc_srv_pipe_exists_by_id ( abstract ) & &
ndr_syntax_id_equal ( transfer , & ndr_transfer_syntax ) ) {
DEBUG ( 3 , ( " check_bind_req: \\ PIPE \\ %s -> \\ PIPE \\ %s \n " ,
rpc_srv_get_pipe_cli_name ( abstract ) ,
rpc_srv_get_pipe_srv_name ( abstract ) ) ) ;
} else {
2008-07-16 02:03:49 +04:00
return false ;
}
context_fns = SMB_MALLOC_P ( struct pipe_rpc_fns ) ;
if ( context_fns = = NULL ) {
DEBUG ( 0 , ( " check_bind_req: malloc() failed! \n " ) ) ;
2000-05-16 00:08:26 +04:00
return False ;
2005-09-30 21:13:37 +04:00
}
2000-05-16 00:08:26 +04:00
2010-08-08 11:23:00 +04:00
context_fns - > next = context_fns - > prev = NULL ;
2010-06-04 00:01:46 +04:00
context_fns - > n_cmds = rpc_srv_get_pipe_num_cmds ( abstract ) ;
context_fns - > cmds = rpc_srv_get_pipe_cmds ( abstract ) ;
2008-07-16 02:03:49 +04:00
context_fns - > context_id = context_id ;
/* add to the list of open contexts */
DLIST_ADD ( p - > contexts , context_fns ) ;
2000-05-16 00:08:26 +04:00
return True ;
}
2008-07-19 22:27:56 +04:00
/**
* Is a named pipe known ?
* @ param [ in ] cli_filename The pipe name requested by the client
* @ result Do we want to serve this ?
*/
2009-02-01 14:03:31 +03:00
bool is_known_pipename ( const char * cli_filename , struct ndr_syntax_id * syntax )
2008-07-19 22:27:56 +04:00
{
const char * pipename = cli_filename ;
2009-10-03 17:33:12 +04:00
NTSTATUS status ;
2008-07-19 22:27:56 +04:00
if ( strnequal ( pipename , " \\ PIPE \\ " , 6 ) ) {
pipename + = 5 ;
}
if ( * pipename = = ' \\ ' ) {
pipename + = 1 ;
}
if ( lp_disable_spoolss ( ) & & strequal ( pipename , " spoolss " ) ) {
DEBUG ( 10 , ( " refusing spoolss access \n " ) ) ;
return false ;
}
2010-06-04 00:01:46 +04:00
if ( rpc_srv_get_pipe_interface_by_cli_name ( pipename , syntax ) ) {
return true ;
2008-07-19 22:27:56 +04:00
}
2009-10-03 17:33:12 +04:00
status = smb_probe_module ( " rpc " , pipename ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " is_known_pipename: %s unknown \n " , cli_filename ) ) ;
return false ;
}
DEBUG ( 10 , ( " is_known_pipename: %s loaded dynamically \n " , pipename ) ) ;
/*
* Scan the list again for the interface id
*/
2010-06-04 00:01:46 +04:00
if ( rpc_srv_get_pipe_interface_by_cli_name ( pipename , syntax ) ) {
return true ;
2009-10-03 17:33:12 +04:00
}
DEBUG ( 10 , ( " is_known_pipename: pipe %s did not register itself! \n " ,
pipename ) ) ;
2008-07-19 22:27:56 +04:00
return false ;
}
2005-09-30 21:13:37 +04:00
/*******************************************************************
Handle a SPNEGO krb5 bind auth .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-28 12:16:34 +04:00
static bool pipe_spnego_auth_bind_kerberos ( struct pipes_struct * p ,
2010-07-11 19:15:40 +04:00
TALLOC_CTX * mem_ctx ,
2010-07-09 00:02:08 +04:00
struct dcerpc_auth * pauth_info ,
DATA_BLOB * psecblob ,
2010-07-11 19:15:40 +04:00
DATA_BLOB * response )
2005-09-30 21:13:37 +04:00
{
return False ;
}
/*******************************************************************
Handle the first part of a SPNEGO bind auth .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-28 12:16:34 +04:00
static bool pipe_spnego_auth_bind_negotiate ( struct pipes_struct * p ,
2010-07-11 19:15:40 +04:00
TALLOC_CTX * mem_ctx ,
2010-07-09 00:02:08 +04:00
struct dcerpc_auth * pauth_info ,
2010-07-11 19:15:40 +04:00
DATA_BLOB * response )
2005-09-30 21:13:37 +04:00
{
2010-09-02 01:09:52 +04:00
DATA_BLOB secblob = data_blob_null ;
DATA_BLOB chal = data_blob_null ;
2005-09-30 21:13:37 +04:00
char * OIDs [ ASN1_MAX_OIDS ] ;
int i ;
NTSTATUS status ;
2008-02-15 05:08:23 +03:00
bool got_kerberos_mechanism = false ;
2010-09-02 01:09:52 +04:00
bool ret ;
2005-09-30 21:13:37 +04:00
2010-07-09 00:02:08 +04:00
if ( pauth_info - > credentials . data [ 0 ] ! = ASN1_APPLICATION ( 0 ) ) {
2010-09-02 01:09:52 +04:00
ret = false ;
goto done ;
2005-09-30 21:13:37 +04:00
}
/* parse out the OIDs and the first sec blob */
2010-09-02 01:09:52 +04:00
ret = spnego_parse_negTokenInit ( talloc_tos ( ) ,
pauth_info - > credentials , OIDs , NULL , & secblob ) ;
if ( ! ret ) {
DEBUG ( 0 , ( __location__ " : Failed to parse the secblob. \n " ) ) ;
goto done ;
2005-09-30 21:13:37 +04:00
}
2010-09-02 01:09:52 +04:00
if ( strcmp ( OID_KERBEROS5 , OIDs [ 0 ] ) = = 0 | |
strcmp ( OID_KERBEROS5_OLD , OIDs [ 0 ] ) = = 0 ) {
2008-02-15 05:08:23 +03:00
got_kerberos_mechanism = true ;
2005-09-30 21:13:37 +04:00
}
2010-09-02 01:09:52 +04:00
for ( i = 0 ; OIDs [ i ] ; i + + ) {
DEBUG ( 3 , ( __location__ " : Got OID %s \n " , OIDs [ i ] ) ) ;
2008-10-22 16:06:08 +04:00
TALLOC_FREE ( OIDs [ i ] ) ;
2005-09-30 21:13:37 +04:00
}
2010-09-02 01:09:52 +04:00
DEBUG ( 3 , ( __location__ " : Got secblob of size %lu \n " ,
( unsigned long ) secblob . length ) ) ;
2005-09-30 21:13:37 +04:00
2010-09-02 01:09:52 +04:00
if ( got_kerberos_mechanism & &
( ( lp_security ( ) = = SEC_ADS ) | | USE_KERBEROS_KEYTAB ) ) {
2010-07-11 19:15:40 +04:00
ret = pipe_spnego_auth_bind_kerberos ( p , mem_ctx , pauth_info ,
& secblob , response ) ;
2010-09-02 01:09:52 +04:00
goto done ;
2005-09-30 21:13:37 +04:00
}
2010-07-20 21:26:36 +04:00
/* Free any previous auth type. */
free_pipe_auth_data ( & p - > auth ) ;
2010-09-02 01:09:52 +04:00
p - > auth . a_u . auth_ntlmssp_state = NULL ;
2005-09-30 21:13:37 +04:00
2008-02-15 05:08:23 +03:00
if ( ! got_kerberos_mechanism ) {
/* Initialize the NTLM engine. */
2010-09-02 01:09:52 +04:00
status = ntlmssp_server_auth_start ( p ,
( pauth_info - > auth_level = =
DCERPC_AUTH_LEVEL_INTEGRITY ) ,
( pauth_info - > auth_level = =
DCERPC_AUTH_LEVEL_PRIVACY ) ,
true , & secblob , & chal ,
& p - > auth . a_u . auth_ntlmssp_state ) ;
2005-09-30 21:13:37 +04:00
2010-09-02 01:09:52 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( __location__ " : Failed to start NTLMSSP "
" auth (%s). \n " , nt_errstr ( status ) ) ) ;
ret = false ;
goto done ;
2008-02-15 05:08:23 +03:00
}
2005-09-30 21:13:37 +04:00
2008-02-15 05:08:23 +03:00
/* Generate the response blob we need for step 2 of the bind. */
2010-09-02 01:09:52 +04:00
* response = spnego_gen_auth_response (
mem_ctx , & chal ,
NT_STATUS_MORE_PROCESSING_REQUIRED ,
OID_NTLMSSP ) ;
2008-02-15 05:08:23 +03:00
} else {
/*
* SPNEGO negotiate down to NTLMSSP . The subsequent
* code to process follow - up packets is not complete
* yet . JRA .
*/
2010-07-21 03:17:58 +04:00
* response = spnego_gen_auth_response ( mem_ctx , NULL ,
2008-02-15 05:08:23 +03:00
NT_STATUS_MORE_PROCESSING_REQUIRED ,
OID_NTLMSSP ) ;
}
2005-09-30 21:13:37 +04:00
p - > auth . auth_data_free_func = & free_pipe_ntlmssp_auth_data ;
2010-07-20 21:26:36 +04:00
p - > auth . auth_type = DCERPC_AUTH_TYPE_SPNEGO ;
p - > auth . spnego_type = PIPE_AUTH_TYPE_SPNEGO_NTLMSSP ;
2005-09-30 21:13:37 +04:00
2010-09-02 01:09:52 +04:00
ret = true ;
2005-09-30 21:13:37 +04:00
2010-09-02 01:09:52 +04:00
done :
2005-09-30 21:13:37 +04:00
data_blob_free ( & secblob ) ;
data_blob_free ( & chal ) ;
2010-09-02 01:09:52 +04:00
return ret ;
2005-09-30 21:13:37 +04:00
}
/*******************************************************************
Handle the second part of a SPNEGO bind auth .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-28 12:16:34 +04:00
static bool pipe_spnego_auth_bind_continue ( struct pipes_struct * p ,
2010-07-12 01:07:19 +04:00
TALLOC_CTX * mem_ctx ,
2010-07-10 03:34:34 +04:00
struct dcerpc_auth * pauth_info ,
2010-07-12 01:07:19 +04:00
DATA_BLOB * response )
2005-09-30 21:13:37 +04:00
{
2010-09-02 01:09:52 +04:00
DATA_BLOB auth_blob = data_blob_null ;
DATA_BLOB auth_reply = data_blob_null ;
NTSTATUS status ;
bool ret ;
2005-09-30 21:13:37 +04:00
2008-02-15 05:08:23 +03:00
/*
* NB . If we ' ve negotiated down from krb5 to NTLMSSP we ' ll currently
* fail here as ' a ' = = NULL .
*/
2010-07-20 21:26:36 +04:00
if ( p - > auth . auth_type ! = DCERPC_AUTH_TYPE_SPNEGO | |
2010-09-02 01:09:52 +04:00
p - > auth . spnego_type ! = PIPE_AUTH_TYPE_SPNEGO_NTLMSSP | |
p - > auth . a_u . auth_ntlmssp_state = = NULL ) {
DEBUG ( 0 , ( __location__ " : not in NTLMSSP auth state. \n " ) ) ;
2005-09-30 21:13:37 +04:00
goto err ;
}
2010-07-10 03:34:34 +04:00
if ( pauth_info - > credentials . data [ 0 ] ! = ASN1_CONTEXT ( 1 ) ) {
2010-09-02 01:09:52 +04:00
DEBUG ( 0 , ( __location__ " : invalid SPNEGO blob type. \n " ) ) ;
2005-09-30 21:13:37 +04:00
goto err ;
}
2010-09-02 01:09:52 +04:00
ret = spnego_parse_auth ( talloc_tos ( ) ,
pauth_info - > credentials , & auth_blob ) ;
if ( ! ret ) {
DEBUG ( 0 , ( __location__ " : invalid SPNEGO blob. \n " ) ) ;
2005-09-30 21:13:37 +04:00
goto err ;
}
2010-09-02 01:09:52 +04:00
status = ntlmssp_server_step ( p - > auth . a_u . auth_ntlmssp_state ,
p , & auth_blob , & auth_reply ) ;
if ( NT_STATUS_EQUAL ( status ,
NT_STATUS_MORE_PROCESSING_REQUIRED ) | |
auth_reply . length ) {
DEBUG ( 0 , ( __location__ " : This was supposed to be the final "
" leg, but crypto machinery claims a response is "
" needed, aborting auth! \n " ) ) ;
goto err ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Auth failed (%s) \n " , nt_errstr ( status ) ) ) ;
goto err ;
}
2008-02-15 05:08:23 +03:00
2010-09-02 01:09:52 +04:00
ret = pipe_ntlmssp_verify_final ( p ,
p - > auth . a_u . auth_ntlmssp_state ,
p - > auth . auth_level ,
p - > client_id , & p - > syntax ,
& p - > server_info ) ;
if ( ! ret ) {
2005-09-30 21:13:37 +04:00
goto err ;
}
data_blob_free ( & auth_blob ) ;
2006-01-27 05:35:08 +03:00
/* Generate the spnego "accept completed" blob - no incoming data. */
2010-09-02 01:09:52 +04:00
* response = spnego_gen_auth_response ( mem_ctx , & auth_reply ,
NT_STATUS_OK , OID_NTLMSSP ) ;
2006-01-27 05:35:08 +03:00
2005-09-30 21:13:37 +04:00
data_blob_free ( & auth_reply ) ;
2010-09-02 01:09:52 +04:00
p - > pipe_bound = true ;
return true ;
2005-09-30 21:13:37 +04:00
2010-09-02 01:09:52 +04:00
err :
2005-09-30 21:13:37 +04:00
data_blob_free ( & auth_blob ) ;
data_blob_free ( & auth_reply ) ;
2010-07-18 00:34:33 +04:00
free_pipe_auth_data ( & p - > auth ) ;
2005-09-30 21:13:37 +04:00
2010-09-02 01:09:52 +04:00
return false ;
2005-09-30 21:13:37 +04:00
}
/*******************************************************************
Handle an schannel bind auth .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-28 12:16:34 +04:00
static bool pipe_schannel_auth_bind ( struct pipes_struct * p ,
2010-07-11 19:15:40 +04:00
TALLOC_CTX * mem_ctx ,
struct dcerpc_auth * auth_info ,
DATA_BLOB * response )
2005-09-30 21:13:37 +04:00
{
2009-09-08 17:31:01 +04:00
struct NL_AUTH_MESSAGE neg ;
2009-09-11 04:20:59 +04:00
struct NL_AUTH_MESSAGE reply ;
2007-10-19 04:40:25 +04:00
bool ret ;
2009-08-26 00:38:55 +04:00
NTSTATUS status ;
struct netlogon_creds_CredentialState * creds ;
2008-06-24 16:33:31 +04:00
DATA_BLOB session_key ;
2009-09-08 17:31:01 +04:00
enum ndr_err_code ndr_err ;
2010-07-09 00:02:08 +04:00
ndr_err = ndr_pull_struct_blob (
2010-07-11 19:15:40 +04:00
& auth_info - > credentials , mem_ctx , & neg ,
2010-07-09 00:02:08 +04:00
( ndr_pull_flags_fn_t ) ndr_pull_NL_AUTH_MESSAGE ) ;
2009-09-08 17:31:01 +04:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2005-10-07 05:46:19 +04:00
DEBUG ( 0 , ( " pipe_schannel_auth_bind: Could not unmarshal SCHANNEL auth neg \n " ) ) ;
2009-09-08 17:31:01 +04:00
return false ;
}
if ( DEBUGLEVEL > = 10 ) {
NDR_PRINT_DEBUG ( NL_AUTH_MESSAGE , & neg ) ;
}
if ( ! ( neg . Flags & NL_FLAG_OEM_NETBIOS_COMPUTER_NAME ) ) {
DEBUG ( 0 , ( " pipe_schannel_auth_bind: Did not receive netbios computer name \n " ) ) ;
return false ;
2005-09-30 21:13:37 +04:00
}
2006-02-18 04:21:18 +03:00
/*
2009-09-08 17:31:01 +04:00
* The neg . oem_netbios_computer . a key here must match the remote computer name
2006-02-18 04:21:18 +03:00
* given in the DOM_CLNT_SRV . uni_comp_name used on all netlogon pipe
* operations that use credentials .
*/
2005-10-07 05:46:19 +04:00
become_root ( ) ;
2010-05-10 02:42:06 +04:00
status = schannel_get_creds_state ( p , lp_private_dir ( ) ,
neg . oem_netbios_computer . a , & creds ) ;
2005-10-07 05:46:19 +04:00
unbecome_root ( ) ;
2009-08-26 00:38:55 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2005-10-07 05:46:19 +04:00
DEBUG ( 0 , ( " pipe_schannel_auth_bind: Attempt to bind using schannel without successful serverauth2 \n " ) ) ;
2005-09-30 21:13:37 +04:00
return False ;
}
2009-09-16 02:26:17 +04:00
p - > auth . a_u . schannel_auth = talloc ( p , struct schannel_state ) ;
2005-09-30 21:13:37 +04:00
if ( ! p - > auth . a_u . schannel_auth ) {
2009-08-26 00:38:55 +04:00
TALLOC_FREE ( creds ) ;
2005-09-30 21:13:37 +04:00
return False ;
}
2009-09-16 02:26:17 +04:00
p - > auth . a_u . schannel_auth - > state = SCHANNEL_STATE_START ;
2005-09-30 21:13:37 +04:00
p - > auth . a_u . schannel_auth - > seq_num = 0 ;
2009-09-16 02:26:17 +04:00
p - > auth . a_u . schannel_auth - > initiator = false ;
p - > auth . a_u . schannel_auth - > creds = creds ;
2005-09-30 21:13:37 +04:00
/*
* JRA . Should we also copy the schannel session key into the pipe session key p - > session_key
2006-02-16 02:15:55 +03:00
* here ? We do that for NTLMSSP , but the session key is already set up from the vuser
2005-09-30 21:13:37 +04:00
* struct of the person who opened the pipe . I need to test this further . JRA .
2006-06-06 00:38:21 +04:00
*
* VL . As we are mapping this to guest set the generic key
* " SystemLibraryDTC " key here . It ' s a bit difficult to test against
* W2k3 , as it does not allow schannel binds against SAMR and LSA
* anymore .
2005-09-30 21:13:37 +04:00
*/
2008-06-24 16:33:31 +04:00
session_key = generic_session_key ( ) ;
if ( session_key . data = = NULL ) {
2006-06-06 00:38:21 +04:00
DEBUG ( 0 , ( " pipe_schannel_auth_bind: Could not alloc session "
" key \n " ) ) ;
2008-06-24 16:33:31 +04:00
return false ;
}
ret = server_info_set_session_key ( p - > server_info , session_key ) ;
data_blob_free ( & session_key ) ;
if ( ! ret ) {
DEBUG ( 0 , ( " server_info_set_session_key failed \n " ) ) ;
return false ;
2006-06-06 00:38:21 +04:00
}
2005-09-30 21:13:37 +04:00
/*** SCHANNEL verifier ***/
2009-09-11 04:20:59 +04:00
reply . MessageType = NL_NEGOTIATE_RESPONSE ;
reply . Flags = 0 ;
reply . Buffer . dummy = 5 ; /* ??? actually I don't think
* this has any meaning
* here - gd */
2010-07-11 19:15:40 +04:00
ndr_err = ndr_push_struct_blob ( response , mem_ctx , & reply ,
2009-09-11 04:20:59 +04:00
( ndr_push_flags_fn_t ) ndr_push_NL_AUTH_MESSAGE ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 0 , ( " Failed to marshall NL_AUTH_MESSAGE. \n " ) ) ;
return false ;
2005-09-30 21:13:37 +04:00
}
2009-09-11 04:20:59 +04:00
if ( DEBUGLEVEL > = 10 ) {
NDR_PRINT_DEBUG ( NL_AUTH_MESSAGE , & reply ) ;
}
2005-09-30 21:13:37 +04:00
DEBUG ( 10 , ( " pipe_schannel_auth_bind: schannel auth: domain [%s] myname [%s] \n " ,
2009-09-08 17:31:01 +04:00
neg . oem_netbios_domain . a , neg . oem_netbios_computer . a ) ) ;
2005-09-30 21:13:37 +04:00
/* We're finished with this bind - no more packets. */
2010-07-18 00:01:07 +04:00
p - > auth . auth_data_free_func = & free_pipe_schannel_auth_data ;
2010-07-20 21:26:36 +04:00
p - > auth . auth_type = DCERPC_AUTH_TYPE_SCHANNEL ;
2005-09-30 21:13:37 +04:00
p - > pipe_bound = True ;
return True ;
}
/*******************************************************************
Handle an NTLMSSP bind auth .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-28 12:16:34 +04:00
static bool pipe_ntlmssp_auth_bind ( struct pipes_struct * p ,
2010-07-11 19:15:40 +04:00
TALLOC_CTX * mem_ctx ,
struct dcerpc_auth * auth_info ,
DATA_BLOB * response )
2005-09-30 21:13:37 +04:00
{
NTSTATUS status ;
2010-07-09 00:02:08 +04:00
if ( strncmp ( ( char * ) auth_info - > credentials . data , " NTLMSSP " , 7 ) ! = 0 ) {
DEBUG ( 0 , ( " Failed to read NTLMSSP in blob \n " ) ) ;
2010-09-02 01:09:52 +04:00
return false ;
2005-09-30 21:13:37 +04:00
}
/* We have an NTLMSSP blob. */
2010-09-02 01:09:52 +04:00
status = ntlmssp_server_auth_start ( p ,
( auth_info - > auth_level = =
DCERPC_AUTH_LEVEL_INTEGRITY ) ,
( auth_info - > auth_level = =
DCERPC_AUTH_LEVEL_PRIVACY ) ,
true ,
& auth_info - > credentials ,
response ,
& p - > auth . a_u . auth_ntlmssp_state ) ;
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_OK ) ) {
DEBUG ( 0 , ( __location__ " : auth_ntlmssp_start failed: %s \n " ,
nt_errstr ( status ) ) ) ;
return false ;
2005-09-30 21:13:37 +04:00
}
2010-07-11 19:15:40 +04:00
/* Make sure data is bound to the memctx, to be freed the caller */
talloc_steal ( mem_ctx , response - > data ) ;
2005-09-30 21:13:37 +04:00
p - > auth . auth_data_free_func = & free_pipe_ntlmssp_auth_data ;
2010-07-20 21:26:36 +04:00
p - > auth . auth_type = DCERPC_AUTH_TYPE_NTLMSSP ;
2005-09-30 21:13:37 +04:00
2010-09-02 01:09:52 +04:00
DEBUG ( 10 , ( __location__ " : NTLMSSP auth started \n " ) ) ;
2005-09-30 21:13:37 +04:00
2010-09-02 01:09:52 +04:00
return true ;
2005-09-30 21:13:37 +04:00
}
2010-08-27 23:23:20 +04:00
/*******************************************************************
Handle a GSSAPI bind auth .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static bool pipe_gssapi_auth_bind ( struct pipes_struct * p ,
TALLOC_CTX * mem_ctx ,
struct dcerpc_auth * auth_info ,
DATA_BLOB * response )
{
NTSTATUS status ;
struct gse_context * gse_ctx = NULL ;
/* Let's init the gssapi machinery for this connection */
/* by passing NULL, the code will attempt to set a default
* keytab based on configuration options */
status = gse_init_server ( p ,
2010-09-02 01:27:56 +04:00
( auth_info - > auth_level = =
DCERPC_AUTH_LEVEL_INTEGRITY ) ,
( auth_info - > auth_level = =
DCERPC_AUTH_LEVEL_PRIVACY ) ,
2010-08-27 23:23:20 +04:00
GSS_C_DCE_STYLE ,
2010-09-02 03:05:43 +04:00
NULL ,
2010-08-27 23:23:20 +04:00
& gse_ctx ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Failed to init dcerpc gssapi server (%s) \n " ,
nt_errstr ( status ) ) ) ;
goto err ;
}
status = gse_get_server_auth_token ( mem_ctx , gse_ctx ,
& auth_info - > credentials ,
response ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Failed to parse initial client token (%s) \n " ,
nt_errstr ( status ) ) ) ;
goto err ;
}
p - > auth . a_u . gssapi_state = gse_ctx ;
p - > auth . auth_data_free_func = & free_pipe_gssapi_auth_data ;
p - > auth . auth_type = DCERPC_AUTH_TYPE_KRB5 ;
DEBUG ( 10 , ( " KRB5 auth started \n " ) ) ;
return true ;
err :
TALLOC_FREE ( gse_ctx ) ;
return false ;
}
static NTSTATUS finalize_gssapi_bind ( TALLOC_CTX * mem_ctx ,
struct gse_context * gse_ctx ,
struct client_address * client_id ,
struct auth_serversupplied_info * * sinfo )
{
TALLOC_CTX * tmp_ctx ;
DATA_BLOB session_key ;
DATA_BLOB auth_data ;
DATA_BLOB pac ;
bool bret ;
NTSTATUS status ;
char * princ_name ;
time_t tgs_authtime ;
NTTIME tgs_authtime_nttime ;
struct PAC_DATA * pac_data ;
struct PAC_LOGON_NAME * logon_name = NULL ;
struct PAC_LOGON_INFO * logon_info = NULL ;
enum ndr_err_code ndr_err ;
unsigned int i ;
bool is_mapped ;
bool is_guest ;
char * ntuser ;
char * ntdomain ;
char * username ;
struct passwd * pw ;
struct auth_serversupplied_info * server_info ;
tmp_ctx = talloc_new ( mem_ctx ) ;
if ( ! tmp_ctx ) {
return NT_STATUS_NO_MEMORY ;
}
/* Finally - if the pipe negotiated integrity (sign) or privacy (seal)
ensure the underlying flags are also set . If not we should
refuse the bind . */
status = gse_verify_server_auth_flags ( gse_ctx ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Requested Security Layers not honored! \n " ) ) ;
goto done ;
}
status = gse_get_authz_data ( gse_ctx , tmp_ctx , & auth_data ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
/* TODO: Fetch user by principal name ? */
status = NT_STATUS_ACCESS_DENIED ;
goto done ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
bret = unwrap_pac ( tmp_ctx , & auth_data , & pac ) ;
if ( ! bret ) {
DEBUG ( 1 , ( " Failed to unwrap PAC \n " ) ) ;
status = NT_STATUS_ACCESS_DENIED ;
goto done ;
}
status = gse_get_client_name ( gse_ctx , tmp_ctx , & princ_name ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
status = gse_get_authtime ( gse_ctx , & tgs_authtime ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
unix_to_nt_time ( & tgs_authtime_nttime , tgs_authtime ) ;
pac_data = talloc_zero ( tmp_ctx , struct PAC_DATA ) ;
if ( ! pac_data ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
ndr_err = ndr_pull_struct_blob ( & pac , pac_data , pac_data ,
( ndr_pull_flags_fn_t ) ndr_pull_PAC_DATA ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 1 , ( " Failed to parse the PAC for %s \n " , princ_name ) ) ;
status = ndr_map_error2ntstatus ( ndr_err ) ;
goto done ;
}
/* get logon name and logon info */
for ( i = 0 ; i < pac_data - > num_buffers ; i + + ) {
struct PAC_BUFFER * data_buf = & pac_data - > buffers [ i ] ;
switch ( data_buf - > type ) {
case PAC_TYPE_LOGON_INFO :
if ( ! data_buf - > info ) {
break ;
}
logon_info = data_buf - > info - > logon_info . info ;
break ;
case PAC_TYPE_LOGON_NAME :
logon_name = & data_buf - > info - > logon_name ;
break ;
default :
break ;
}
}
if ( ! logon_info ) {
DEBUG ( 1 , ( " Invalid PAC data, missing logon info! \n " ) ) ;
status = NT_STATUS_NOT_FOUND ;
goto done ;
}
if ( ! logon_name ) {
DEBUG ( 1 , ( " Invalid PAC data, missing logon info! \n " ) ) ;
status = NT_STATUS_NOT_FOUND ;
goto done ;
}
/* check time */
if ( tgs_authtime_nttime ! = logon_name - > logon_time ) {
DEBUG ( 1 , ( " Logon time mismatch between ticket and PAC! \n "
" PAC Time = %s | Ticket Time = %s \n " ,
nt_time_string ( tmp_ctx , logon_name - > logon_time ) ,
nt_time_string ( tmp_ctx , tgs_authtime_nttime ) ) ) ;
status = NT_STATUS_ACCESS_DENIED ;
goto done ;
}
/* TODO: Should we check princ_name against account_name in
* logon_name ? Are they supposed to be identical , or can an
* account_name be different from the UPN ? */
status = get_user_from_kerberos_info ( talloc_tos ( ) , client_id - > name ,
princ_name , logon_info ,
& is_mapped , & is_guest ,
& ntuser , & ntdomain ,
& username , & pw ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Failed to map kerberos principal to system user "
" (%s) \n " , nt_errstr ( status ) ) ) ;
status = NT_STATUS_ACCESS_DENIED ;
goto done ;
}
/* TODO: save PAC data in netsamlogon cache ? */
status = make_server_info_krb5 ( mem_ctx ,
ntuser , ntdomain , username , pw ,
logon_info , is_guest , & server_info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Failed to map kerberos pac to server info (%s) \n " ,
nt_errstr ( status ) ) ) ;
status = NT_STATUS_ACCESS_DENIED ;
goto done ;
}
if ( server_info - > ptok = = NULL ) {
status = create_local_token ( server_info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Failed to create local user token (%s) \n " ,
nt_errstr ( status ) ) ) ;
status = NT_STATUS_ACCESS_DENIED ;
goto done ;
}
}
/* TODO: this is what the ntlmssp code does with the session_key,
* probably need to be moved to an upper level as this will not apply
* to tcp / ip connections */
/*
* We ' re an authenticated bind over smb , so the session key needs to
* be set to " SystemLibraryDTC " . Weird , but this is what Windows
* does . See the RPC - SAMBA3SESSIONKEY .
*/
session_key = generic_session_key ( ) ;
if ( session_key . data = = NULL ) {
status = NT_STATUS_ACCESS_DENIED ;
goto done ;
}
bret = server_info_set_session_key ( server_info , session_key ) ;
if ( ! bret ) {
status = NT_STATUS_ACCESS_DENIED ;
goto done ;
}
data_blob_free ( & session_key ) ;
* sinfo = server_info ;
status = NT_STATUS_OK ;
done :
TALLOC_FREE ( tmp_ctx ) ;
return status ;
}
/*******************************************************************
Process a KRB5 authentication response .
If this function succeeds , the user has been authenticated
and their domain , name and calling workstation stored in
the pipe struct .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS pipe_gssapi_auth_bind_next ( struct pipes_struct * p ,
TALLOC_CTX * mem_ctx ,
struct dcerpc_auth * pauth_info ,
DATA_BLOB * response )
{
struct gse_context * gse_ctx = p - > auth . a_u . gssapi_state ;
NTSTATUS status ;
DEBUG ( 5 , ( __location__ " : pipe %s checking user details \n " ,
get_pipe_name_from_syntax ( talloc_tos ( ) , & p - > syntax ) ) ) ;
status = gse_get_server_auth_token ( mem_ctx , gse_ctx ,
& pauth_info - > credentials ,
response ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
data_blob_free ( response ) ;
return status ;
}
if ( gse_require_more_processing ( gse_ctx ) ) {
/* ask for next leg */
2010-09-02 01:09:52 +04:00
return NT_STATUS_MORE_PROCESSING_REQUIRED ;
2010-08-27 23:23:20 +04:00
}
return NT_STATUS_OK ;
}
2000-03-10 00:45:16 +03:00
/*******************************************************************
Respond to a pipe bind request .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-08-02 18:28:10 +04:00
static bool api_pipe_bind_req ( struct pipes_struct * p ,
struct ncacn_packet * pkt )
2000-03-10 00:45:16 +03:00
{
2010-07-09 00:02:08 +04:00
struct dcerpc_auth auth_info ;
2000-03-10 00:45:16 +03:00
uint16 assoc_gid ;
2009-09-15 21:32:39 +04:00
unsigned int auth_type = DCERPC_AUTH_TYPE_NONE ;
2010-06-04 00:01:46 +04:00
NTSTATUS status ;
struct ndr_syntax_id id ;
2010-07-11 19:48:22 +04:00
union dcerpc_payload u ;
struct dcerpc_ack_ctx bind_ack_ctx ;
2010-07-11 19:15:40 +04:00
DATA_BLOB auth_resp = data_blob_null ;
DATA_BLOB auth_blob = data_blob_null ;
2005-09-30 21:13:37 +04:00
/* No rebinds on a bound pipe - use alter context. */
if ( p - > pipe_bound ) {
2009-02-01 14:03:31 +03:00
DEBUG ( 2 , ( " api_pipe_bind_req: rejecting bind request on bound "
2009-11-08 21:37:53 +03:00
" pipe %s. \n " ,
get_pipe_name_from_syntax ( talloc_tos ( ) , & p - > syntax ) ) ) ;
2010-07-11 18:37:07 +04:00
return setup_bind_nak ( p , pkt ) ;
2005-09-30 21:13:37 +04:00
}
2000-03-10 00:45:16 +03:00
2010-07-10 03:34:34 +04:00
if ( pkt - > u . bind . num_contexts = = 0 ) {
2008-07-13 01:17:23 +04:00
DEBUG ( 0 , ( " api_pipe_bind_req: no rpc contexts around \n " ) ) ;
goto err_exit ;
}
2000-03-10 00:45:16 +03:00
/*
2005-09-30 21:13:37 +04:00
* Try and find the correct pipe name to ensure
* that this is a pipe name we support .
*/
2010-07-10 03:34:34 +04:00
id = pkt - > u . bind . ctx_list [ 0 ] . abstract_syntax ;
2010-06-04 00:01:46 +04:00
if ( rpc_srv_pipe_exists_by_id ( & id ) ) {
DEBUG ( 3 , ( " api_pipe_bind_req: \\ PIPE \\ %s -> \\ PIPE \\ %s \n " ,
rpc_srv_get_pipe_cli_name ( & id ) ,
rpc_srv_get_pipe_srv_name ( & id ) ) ) ;
} else {
2009-02-01 14:03:31 +03:00
status = smb_probe_module (
2009-10-31 21:28:16 +03:00
" rpc " , get_pipe_name_from_syntax (
talloc_tos ( ) ,
2010-07-10 03:34:34 +04:00
& pkt - > u . bind . ctx_list [ 0 ] . abstract_syntax ) ) ;
2009-02-01 14:03:31 +03:00
if ( NT_STATUS_IS_ERR ( status ) ) {
2005-09-30 21:13:37 +04:00
DEBUG ( 3 , ( " api_pipe_bind_req: Unknown pipe name %s in bind request. \n " ,
2009-10-31 21:28:16 +03:00
get_pipe_name_from_syntax (
talloc_tos ( ) ,
2010-07-10 03:34:34 +04:00
& pkt - > u . bind . ctx_list [ 0 ] . abstract_syntax ) ) ) ;
2005-09-30 21:13:37 +04:00
2010-07-11 18:37:07 +04:00
return setup_bind_nak ( p , pkt ) ;
2010-06-04 00:01:46 +04:00
}
if ( rpc_srv_get_pipe_interface_by_cli_name (
get_pipe_name_from_syntax ( talloc_tos ( ) ,
& p - > syntax ) ,
& id ) ) {
DEBUG ( 3 , ( " api_pipe_bind_req: \\ PIPE \\ %s -> \\ PIPE \\ %s \n " ,
rpc_srv_get_pipe_cli_name ( & id ) ,
rpc_srv_get_pipe_srv_name ( & id ) ) ) ;
} else {
2009-02-01 14:03:31 +03:00
DEBUG ( 0 , ( " module %s doesn't provide functions for "
2009-11-08 21:37:53 +03:00
" pipe %s! \n " ,
get_pipe_name_from_syntax ( talloc_tos ( ) ,
& p - > syntax ) ,
get_pipe_name_from_syntax ( talloc_tos ( ) ,
& p - > syntax ) ) ) ;
2010-07-11 18:47:32 +04:00
return setup_bind_nak ( p , pkt ) ;
2005-09-30 21:13:37 +04:00
}
}
DEBUG ( 5 , ( " api_pipe_bind_req: make response. %d \n " , __LINE__ ) ) ;
2010-07-10 03:34:34 +04:00
if ( pkt - > u . bind . assoc_group_id ! = 0 ) {
assoc_gid = pkt - > u . bind . assoc_group_id ;
2010-07-08 09:14:16 +04:00
} else {
assoc_gid = 0x53f0 ;
}
2010-02-18 02:27:59 +03:00
/*
* Create the bind response struct .
*/
/* If the requested abstract synt uuid doesn't match our client pipe,
reject the bind_ack & set the transfer interface synt to all 0 ' s ,
ver 0 ( observed when NT5 attempts to bind to abstract interfaces
unknown to NT4 )
Needed when adding entries to a DACL from NT5 - SK */
2010-07-08 01:14:27 +04:00
if ( check_bind_req ( p ,
2010-07-10 03:34:34 +04:00
& pkt - > u . bind . ctx_list [ 0 ] . abstract_syntax ,
& pkt - > u . bind . ctx_list [ 0 ] . transfer_syntaxes [ 0 ] ,
pkt - > u . bind . ctx_list [ 0 ] . context_id ) ) {
2010-07-11 19:48:22 +04:00
bind_ack_ctx . result = 0 ;
bind_ack_ctx . reason = 0 ;
bind_ack_ctx . syntax = pkt - > u . bind . ctx_list [ 0 ] . transfer_syntaxes [ 0 ] ;
2010-02-18 02:27:59 +03:00
} else {
p - > pipe_bound = False ;
2010-07-11 19:48:22 +04:00
/* Rejection reason: abstract syntax not supported */
bind_ack_ctx . result = DCERPC_BIND_PROVIDER_REJECT ;
bind_ack_ctx . reason = DCERPC_BIND_REASON_ASYNTAX ;
bind_ack_ctx . syntax = null_ndr_syntax_id ;
2010-02-18 02:27:59 +03:00
}
2005-09-30 21:13:37 +04:00
/*
* Check if this is an authenticated bind request .
*/
2010-07-10 03:34:34 +04:00
if ( pkt - > auth_length ) {
2010-02-18 02:27:59 +03:00
/* Quick length check. Won't catch a bad auth footer,
* prevents overrun . */
2010-07-10 03:34:34 +04:00
if ( pkt - > frag_length < RPC_HEADER_LEN +
2010-07-14 21:56:13 +04:00
DCERPC_AUTH_TRAILER_LENGTH +
2010-07-10 03:34:34 +04:00
pkt - > auth_length ) {
2010-02-18 02:27:59 +03:00
DEBUG ( 0 , ( " api_pipe_bind_req: auth_len (%u) "
" too long for fragment %u. \n " ,
2010-07-10 03:34:34 +04:00
( unsigned int ) pkt - > auth_length ,
( unsigned int ) pkt - > frag_length ) ) ;
2010-02-18 02:27:59 +03:00
goto err_exit ;
}
2010-07-11 19:48:22 +04:00
/*
* Decode the authentication verifier .
*/
2010-07-10 03:34:34 +04:00
status = dcerpc_pull_dcerpc_auth ( pkt ,
& pkt - > u . bind . auth_info ,
2010-07-16 23:15:48 +04:00
& auth_info , p - > endian ) ;
2010-07-09 00:02:08 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Unable to unmarshall dcerpc_auth. \n " ) ) ;
2005-09-30 21:13:37 +04:00
goto err_exit ;
}
auth_type = auth_info . auth_type ;
/* Work out if we have to sign or seal etc. */
switch ( auth_info . auth_level ) {
2010-07-09 00:02:08 +04:00
case DCERPC_AUTH_LEVEL_INTEGRITY :
p - > auth . auth_level = DCERPC_AUTH_LEVEL_INTEGRITY ;
break ;
case DCERPC_AUTH_LEVEL_PRIVACY :
p - > auth . auth_level = DCERPC_AUTH_LEVEL_PRIVACY ;
break ;
default :
DEBUG ( 0 , ( " Unexpected auth level (%u). \n " ,
( unsigned int ) auth_info . auth_level ) ) ;
goto err_exit ;
2005-09-30 21:13:37 +04:00
}
2010-07-11 19:48:22 +04:00
switch ( auth_type ) {
2009-09-15 20:30:01 +04:00
case DCERPC_AUTH_TYPE_NTLMSSP :
2010-07-11 19:15:40 +04:00
if ( ! pipe_ntlmssp_auth_bind ( p , pkt ,
& auth_info , & auth_resp ) ) {
2005-09-30 21:13:37 +04:00
goto err_exit ;
}
assoc_gid = 0x7a77 ;
break ;
2009-09-15 20:30:01 +04:00
case DCERPC_AUTH_TYPE_SCHANNEL :
2010-07-11 19:15:40 +04:00
if ( ! pipe_schannel_auth_bind ( p , pkt ,
& auth_info , & auth_resp ) ) {
2005-09-30 21:13:37 +04:00
goto err_exit ;
}
break ;
2009-09-15 20:30:01 +04:00
case DCERPC_AUTH_TYPE_SPNEGO :
2010-07-11 19:15:40 +04:00
if ( ! pipe_spnego_auth_bind_negotiate ( p , pkt ,
& auth_info , & auth_resp ) ) {
2005-09-30 21:13:37 +04:00
goto err_exit ;
}
break ;
2010-08-27 23:23:20 +04:00
case DCERPC_AUTH_TYPE_KRB5 :
if ( ! pipe_gssapi_auth_bind ( p , pkt ,
& auth_info , & auth_resp ) ) {
goto err_exit ;
}
break ;
2009-09-15 21:32:39 +04:00
case DCERPC_AUTH_TYPE_NONE :
2005-09-30 21:13:37 +04:00
break ;
default :
2010-07-11 19:48:22 +04:00
DEBUG ( 0 , ( " Unknown auth type %x requested. \n " , auth_type ) ) ;
2005-09-30 21:13:37 +04:00
goto err_exit ;
2010-07-11 19:48:22 +04:00
}
2005-09-30 21:13:37 +04:00
}
2010-07-11 19:48:22 +04:00
if ( auth_type = = DCERPC_AUTH_TYPE_NONE ) {
/* Unauthenticated bind request. */
/* We're finished - no more packets. */
2010-07-20 21:26:36 +04:00
p - > auth . auth_type = DCERPC_AUTH_TYPE_NONE ;
p - > auth . spnego_type = PIPE_AUTH_TYPE_SPNEGO_NONE ;
2010-07-11 19:48:22 +04:00
/* We must set the pipe auth_level here also. */
p - > auth . auth_level = DCERPC_AUTH_LEVEL_NONE ;
p - > pipe_bound = True ;
/* The session key was initialized from the SMB
* session in make_internal_rpc_pipe_p */
}
ZERO_STRUCT ( u . bind_ack ) ;
u . bind_ack . max_xmit_frag = RPC_MAX_PDU_FRAG_LEN ;
u . bind_ack . max_recv_frag = RPC_MAX_PDU_FRAG_LEN ;
u . bind_ack . assoc_group_id = assoc_gid ;
/* name has to be \PIPE\xxxxx */
u . bind_ack . secondary_address =
talloc_asprintf ( pkt , " \\ PIPE \\ %s " ,
rpc_srv_get_pipe_srv_name ( & id ) ) ;
if ( ! u . bind_ack . secondary_address ) {
DEBUG ( 0 , ( " Out of memory! \n " ) ) ;
goto err_exit ;
}
u . bind_ack . secondary_address_size =
strlen ( u . bind_ack . secondary_address ) + 1 ;
u . bind_ack . num_results = 1 ;
u . bind_ack . ctx_list = & bind_ack_ctx ;
/* NOTE: We leave the auth_info empty so we can calculate the padding
* later and then append the auth_info - - simo */
2010-07-14 02:01:16 +04:00
/*
* Marshall directly into the outgoing PDU space . We
* must do this as we need to set to the bind response
* header and are never sending more than one PDU here .
*/
status = dcerpc_push_ncacn_packet ( p - > mem_ctx ,
DCERPC_PKT_BIND_ACK ,
2010-07-11 19:48:22 +04:00
DCERPC_PFC_FLAG_FIRST |
DCERPC_PFC_FLAG_LAST ,
auth_resp . length ,
pkt - > call_id ,
2010-07-14 02:01:16 +04:00
& u ,
& p - > out_data . frag ) ;
2010-07-11 19:48:22 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Failed to marshall bind_ack packet. (%s) \n " ,
nt_errstr ( status ) ) ) ;
}
2010-07-11 19:15:40 +04:00
if ( auth_resp . length ) {
2010-07-11 19:48:22 +04:00
2010-07-11 19:15:40 +04:00
status = dcerpc_push_dcerpc_auth ( pkt ,
auth_type ,
auth_info . auth_level ,
2010-07-14 19:09:04 +04:00
0 ,
2010-07-11 19:15:40 +04:00
1 , /* auth_context_id */
& auth_resp ,
& auth_blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Marshalling of dcerpc_auth failed. \n " ) ) ;
goto err_exit ;
}
}
2010-07-11 19:48:22 +04:00
/* Now that we have the auth len store it into the right place in
* the dcerpc header */
2010-07-14 02:01:16 +04:00
dcerpc_set_frag_length ( & p - > out_data . frag ,
2010-07-14 19:09:04 +04:00
p - > out_data . frag . length + auth_blob . length ) ;
2005-07-28 00:25:04 +04:00
2010-07-11 19:48:22 +04:00
if ( auth_blob . length ) {
2010-02-18 02:27:59 +03:00
2010-07-14 02:01:16 +04:00
if ( ! data_blob_append ( p - > mem_ctx , & p - > out_data . frag ,
auth_blob . data , auth_blob . length ) ) {
2010-07-11 19:48:22 +04:00
DEBUG ( 0 , ( " Append of auth info failed. \n " ) ) ;
2010-02-18 02:27:59 +03:00
goto err_exit ;
}
2005-09-30 21:13:37 +04:00
}
2005-07-28 00:25:04 +04:00
2005-09-30 21:13:37 +04:00
/*
* Setup the lengths for the initial reply .
*/
2005-07-28 00:25:04 +04:00
2005-09-30 21:13:37 +04:00
p - > out_data . data_sent_length = 0 ;
p - > out_data . current_pdu_sent = 0 ;
2005-07-28 00:25:04 +04:00
2010-07-11 19:15:40 +04:00
TALLOC_FREE ( auth_blob . data ) ;
2005-09-30 21:13:37 +04:00
return True ;
2005-07-28 00:25:04 +04:00
2005-09-30 21:13:37 +04:00
err_exit :
2005-07-28 00:25:04 +04:00
2010-07-14 02:01:16 +04:00
data_blob_free ( & p - > out_data . frag ) ;
2010-07-11 19:15:40 +04:00
TALLOC_FREE ( auth_blob . data ) ;
2010-07-11 18:37:07 +04:00
return setup_bind_nak ( p , pkt ) ;
2005-09-30 21:13:37 +04:00
}
2005-06-03 13:24:48 +04:00
2005-09-30 21:13:37 +04:00
/****************************************************************************
Deal with an alter context call . Can be third part of 3 leg auth request for
SPNEGO calls .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-03-10 00:45:16 +03:00
2010-08-02 18:28:10 +04:00
static bool api_pipe_alter_context ( struct pipes_struct * p ,
struct ncacn_packet * pkt )
2005-09-30 21:13:37 +04:00
{
2010-07-10 03:34:34 +04:00
struct dcerpc_auth auth_info ;
2005-09-30 21:13:37 +04:00
uint16 assoc_gid ;
2010-07-08 09:14:16 +04:00
NTSTATUS status ;
2010-07-12 01:35:02 +04:00
union dcerpc_payload u ;
struct dcerpc_ack_ctx bind_ack_ctx ;
2010-07-12 01:07:19 +04:00
DATA_BLOB auth_resp = data_blob_null ;
DATA_BLOB auth_blob = data_blob_null ;
2010-07-12 01:35:02 +04:00
int pad_len = 0 ;
2005-09-30 21:13:37 +04:00
DEBUG ( 5 , ( " api_pipe_alter_context: make response. %d \n " , __LINE__ ) ) ;
2010-07-10 03:34:34 +04:00
if ( pkt - > u . bind . assoc_group_id ! = 0 ) {
assoc_gid = pkt - > u . bind . assoc_group_id ;
2010-07-08 09:14:16 +04:00
} else {
assoc_gid = 0x53f0 ;
}
2000-03-10 00:45:16 +03:00
/*
* Create the bind response struct .
*/
2000-05-16 00:08:26 +04:00
/* If the requested abstract synt uuid doesn't match our client pipe,
reject the bind_ack & set the transfer interface synt to all 0 ' s ,
ver 0 ( observed when NT5 attempts to bind to abstract interfaces
unknown to NT4 )
Needed when adding entries to a DACL from NT5 - SK */
2010-07-08 01:14:27 +04:00
if ( check_bind_req ( p ,
2010-07-10 03:34:34 +04:00
& pkt - > u . bind . ctx_list [ 0 ] . abstract_syntax ,
& pkt - > u . bind . ctx_list [ 0 ] . transfer_syntaxes [ 0 ] ,
pkt - > u . bind . ctx_list [ 0 ] . context_id ) ) {
2010-07-12 01:35:02 +04:00
bind_ack_ctx . result = 0 ;
bind_ack_ctx . reason = 0 ;
bind_ack_ctx . syntax = pkt - > u . bind . ctx_list [ 0 ] . transfer_syntaxes [ 0 ] ;
2000-05-16 00:08:26 +04:00
} else {
2005-09-30 21:13:37 +04:00
p - > pipe_bound = False ;
2010-07-12 01:35:02 +04:00
/* Rejection reason: abstract syntax not supported */
bind_ack_ctx . result = DCERPC_BIND_PROVIDER_REJECT ;
bind_ack_ctx . reason = DCERPC_BIND_REASON_ASYNTAX ;
bind_ack_ctx . syntax = null_ndr_syntax_id ;
2000-05-16 00:08:26 +04:00
}
2000-03-10 00:45:16 +03:00
2010-02-18 02:27:59 +03:00
/*
* Check if this is an authenticated alter context request .
*/
2010-07-12 01:35:02 +04:00
if ( pkt - > auth_length ) {
2010-02-18 02:27:59 +03:00
/* Quick length check. Won't catch a bad auth footer,
* prevents overrun . */
2010-07-10 03:34:34 +04:00
if ( pkt - > frag_length < RPC_HEADER_LEN +
2010-07-14 21:56:13 +04:00
DCERPC_AUTH_TRAILER_LENGTH +
2010-07-10 03:34:34 +04:00
pkt - > auth_length ) {
2010-02-18 02:27:59 +03:00
DEBUG ( 0 , ( " api_pipe_alter_context: auth_len (%u) "
" too long for fragment %u. \n " ,
2010-07-10 03:34:34 +04:00
( unsigned int ) pkt - > auth_length ,
( unsigned int ) pkt - > frag_length ) ) ;
2010-02-18 02:27:59 +03:00
goto err_exit ;
}
2010-07-10 03:34:34 +04:00
status = dcerpc_pull_dcerpc_auth ( pkt ,
& pkt - > u . bind . auth_info ,
2010-07-16 23:15:48 +04:00
& auth_info , p - > endian ) ;
2010-07-10 03:34:34 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Unable to unmarshall dcerpc_auth. \n " ) ) ;
2010-02-18 02:27:59 +03:00
goto err_exit ;
}
2010-08-27 23:23:20 +04:00
/* We can only finish if the pipe is unbound for now */
if ( p - > pipe_bound ) {
DEBUG ( 0 , ( __location__ " : Pipe already bound, "
" Altering Context not yet supported! \n " ) ) ;
goto err_exit ;
}
2010-02-18 02:27:59 +03:00
2010-08-27 23:23:20 +04:00
switch ( auth_info . auth_type ) {
case DCERPC_AUTH_TYPE_SPNEGO :
if ( ! pipe_spnego_auth_bind_continue ( p , pkt ,
& auth_info ,
& auth_resp ) ) {
goto err_exit ;
}
break ;
2010-07-12 01:07:19 +04:00
2010-08-27 23:23:20 +04:00
case DCERPC_AUTH_TYPE_KRB5 :
status = pipe_gssapi_auth_bind_next ( p , pkt ,
& auth_info ,
& auth_resp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-02-18 02:27:59 +03:00
goto err_exit ;
}
2010-08-27 23:23:20 +04:00
break ;
default :
DEBUG ( 3 , ( __location__ " : Usupported auth type (%d) "
" in alter-context call \n " ,
auth_info . auth_type ) ) ;
goto err_exit ;
2010-02-18 02:27:59 +03:00
}
2010-07-12 01:35:02 +04:00
}
ZERO_STRUCT ( u . alter_resp ) ;
u . alter_resp . max_xmit_frag = RPC_MAX_PDU_FRAG_LEN ;
u . alter_resp . max_recv_frag = RPC_MAX_PDU_FRAG_LEN ;
u . alter_resp . assoc_group_id = assoc_gid ;
/* secondary address CAN be NULL
* as the specs say it ' s ignored .
* It MUST be NULL to have the spoolss working .
*/
u . alter_resp . secondary_address = " " ;
u . alter_resp . secondary_address_size = 1 ;
u . alter_resp . num_results = 1 ;
u . alter_resp . ctx_list = & bind_ack_ctx ;
/* NOTE: We leave the auth_info empty so we can calculate the padding
* later and then append the auth_info - - simo */
2010-07-14 02:01:16 +04:00
/*
* Marshall directly into the outgoing PDU space . We
* must do this as we need to set to the bind response
* header and are never sending more than one PDU here .
*/
status = dcerpc_push_ncacn_packet ( p - > mem_ctx ,
DCERPC_PKT_ALTER_RESP ,
2010-07-12 01:35:02 +04:00
DCERPC_PFC_FLAG_FIRST |
DCERPC_PFC_FLAG_LAST ,
auth_resp . length ,
pkt - > call_id ,
2010-07-14 02:01:16 +04:00
& u ,
& p - > out_data . frag ) ;
2010-07-12 01:35:02 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Failed to marshall bind_ack packet. (%s) \n " ,
nt_errstr ( status ) ) ) ;
2010-02-18 02:27:59 +03:00
}
2010-07-12 01:07:19 +04:00
if ( auth_resp . length ) {
2010-07-12 01:35:02 +04:00
/* Work out any padding needed before the auth footer. */
2010-07-14 02:01:16 +04:00
pad_len = p - > out_data . frag . length % SERVER_NDR_PADDING_SIZE ;
2010-07-12 01:35:02 +04:00
if ( pad_len ) {
pad_len = SERVER_NDR_PADDING_SIZE - pad_len ;
DEBUG ( 10 , ( " auth pad_len = %u \n " ,
( unsigned int ) pad_len ) ) ;
}
2010-07-12 01:07:19 +04:00
status = dcerpc_push_dcerpc_auth ( pkt ,
auth_info . auth_type ,
auth_info . auth_level ,
2010-07-12 01:35:02 +04:00
pad_len ,
2010-07-12 01:07:19 +04:00
1 , /* auth_context_id */
& auth_resp ,
& auth_blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Marshalling of dcerpc_auth failed. \n " ) ) ;
goto err_exit ;
}
2000-03-10 00:45:16 +03:00
}
2010-07-12 01:35:02 +04:00
/* Now that we have the auth len store it into the right place in
* the dcerpc header */
2010-07-14 02:01:16 +04:00
dcerpc_set_frag_length ( & p - > out_data . frag ,
p - > out_data . frag . length +
pad_len + auth_blob . length ) ;
2000-03-10 00:45:16 +03:00
2010-07-12 01:35:02 +04:00
if ( auth_resp . length ) {
if ( pad_len ) {
2010-02-18 02:27:59 +03:00
char pad [ SERVER_NDR_PADDING_SIZE ] ;
memset ( pad , ' \0 ' , SERVER_NDR_PADDING_SIZE ) ;
2010-07-14 02:01:16 +04:00
if ( ! data_blob_append ( p - > mem_ctx ,
& p - > out_data . frag ,
pad , pad_len ) ) {
2010-07-12 01:35:02 +04:00
DEBUG ( 0 , ( " api_pipe_bind_req: failed to add "
" %u bytes of pad data. \n " ,
( unsigned int ) pad_len ) ) ;
2010-02-18 02:27:59 +03:00
goto err_exit ;
}
}
2010-07-14 02:01:16 +04:00
if ( ! data_blob_append ( p - > mem_ctx , & p - > out_data . frag ,
auth_blob . data , auth_blob . length ) ) {
2010-07-12 01:35:02 +04:00
DEBUG ( 0 , ( " Append of auth info failed. \n " ) ) ;
2010-02-18 02:27:59 +03:00
goto err_exit ;
}
2000-03-10 00:45:16 +03:00
}
/*
* Setup the lengths for the initial reply .
*/
p - > out_data . data_sent_length = 0 ;
p - > out_data . current_pdu_sent = 0 ;
2010-07-12 01:07:19 +04:00
TALLOC_FREE ( auth_blob . data ) ;
2000-03-10 00:45:16 +03:00
return True ;
err_exit :
2010-07-14 02:01:16 +04:00
data_blob_free ( & p - > out_data . frag ) ;
2010-07-12 01:07:19 +04:00
TALLOC_FREE ( auth_blob . data ) ;
2010-07-11 18:37:07 +04:00
return setup_bind_nak ( p , pkt ) ;
2000-03-10 00:45:16 +03:00
}
1998-11-12 19:07:00 +03:00
2003-08-15 01:14:28 +04:00
/****************************************************************************
Find the set of RPC functions associated with this context_id
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static PIPE_RPC_FNS * find_pipe_fns_by_context ( PIPE_RPC_FNS * list , uint32 context_id )
{
PIPE_RPC_FNS * fns = NULL ;
2009-01-06 13:32:07 +03:00
2003-08-15 01:14:28 +04:00
if ( ! list ) {
DEBUG ( 0 , ( " find_pipe_fns_by_context: ERROR! No context list for pipe! \n " ) ) ;
return NULL ;
}
2009-01-06 13:32:07 +03:00
2009-01-06 13:32:46 +03:00
for ( fns = list ; fns ; fns = fns - > next ) {
if ( fns - > context_id = = context_id )
return fns ;
2003-08-15 01:14:28 +04:00
}
2009-01-06 13:32:46 +03:00
return NULL ;
2003-08-15 01:14:28 +04:00
}
2010-07-28 12:16:34 +04:00
static bool api_rpcTNP ( struct pipes_struct * p , struct ncacn_packet * pkt ,
2008-07-26 13:25:24 +04:00
const struct api_struct * api_rpc_cmds , int n_cmds ) ;
2000-03-10 00:45:16 +03:00
/****************************************************************************
Find the correct RPC function to call for this request .
If the pipe is authenticated then become the correct UNIX user
before doing the call .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-08-02 18:28:10 +04:00
static bool api_pipe_request ( struct pipes_struct * p ,
struct ncacn_packet * pkt )
delineation between smb and msrpc more marked. smbd now constructs
pdus, and then feeds them over either a "local" function call or a "remote"
function call to an msrpc service. the "remote" msrpc daemon, on the
other side of a unix socket, then calls the same "local" function that
smbd would, if the msrpc service were being run from inside smbd.
this allows a transition from local msrpc services (inside the same smbd
process) to remote (over a unix socket).
removed reference to pipes_struct in msrpc services. all msrpc processing
functions take rpcsrv_struct which is a structure containing state info
for the msrpc functions to decode and create pdus.
created become_vuser() which does everything not related to connection_struct
that become_user() does.
removed, as best i could, connection_struct dependencies from the nt spoolss
printing code.
todo: remove dcinfo from rpcsrv_struct because this stores NETLOGON-specific
info on a per-connection basis, and if the connection dies then so does
the info, and that's a fairly serious problem.
had to put pretty much everything that is in user_struct into parse_creds.c
to feed unix user info over to the msrpc daemons. why? because it's
expensive to do unix password/group database lookups, and it's definitely
expensive to do nt user profile lookups, not to mention pretty difficult
and if you did either of these it would introduce a complication /
unnecessary interdependency. so, send uid/gid/num_groups/gid_t* +
SID+num_rids+domain_group_rids* + unix username + nt username + nt domain
+ user session key etc. this is the MINIMUM info identified so far that's
actually implemented. missing bits include the called and calling
netbios names etc. (basically, anything that can be loaded into
standard_sub() and standard_sub_basic()...)
(This used to be commit aa3c659a8dba0437c17c60055a6ed30fdfecdb6d)
1999-12-12 04:25:49 +03:00
{
2007-10-19 04:40:25 +04:00
bool ret = False ;
bool changed_user = False ;
2003-08-15 01:14:28 +04:00
PIPE_RPC_FNS * pipe_fns ;
2009-01-06 13:32:07 +03:00
2007-10-11 00:34:30 +04:00
if ( p - > pipe_bound & &
2010-07-20 21:26:36 +04:00
( ( p - > auth . auth_type = = DCERPC_AUTH_TYPE_NTLMSSP ) | |
( ( p - > auth . auth_type = = DCERPC_AUTH_TYPE_SPNEGO ) & &
( p - > auth . spnego_type = = PIPE_AUTH_TYPE_SPNEGO_NTLMSSP ) ) ) ) {
2000-03-10 00:45:16 +03:00
if ( ! become_authenticated_pipe_user ( p ) ) {
2010-07-13 23:43:44 +04:00
data_blob_free ( & p - > out_data . rdata ) ;
2000-03-10 00:45:16 +03:00
return False ;
}
2005-09-30 21:13:37 +04:00
changed_user = True ;
2000-03-10 00:45:16 +03:00
}
2009-11-08 21:37:53 +03:00
DEBUG ( 5 , ( " Requested \\ PIPE \\ %s \n " ,
get_pipe_name_from_syntax ( talloc_tos ( ) , & p - > syntax ) ) ) ;
2009-01-06 13:32:07 +03:00
2003-08-15 01:14:28 +04:00
/* get the set of RPC functions for this context */
2009-01-06 13:32:07 +03:00
2010-07-10 03:34:34 +04:00
pipe_fns = find_pipe_fns_by_context ( p - > contexts ,
pkt - > u . request . context_id ) ;
2009-01-06 13:32:07 +03:00
2003-08-15 01:14:28 +04:00
if ( pipe_fns ) {
2007-08-30 23:48:31 +04:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2010-07-10 03:34:34 +04:00
ret = api_rpcTNP ( p , pkt , pipe_fns - > cmds , pipe_fns - > n_cmds ) ;
2007-08-30 23:48:31 +04:00
TALLOC_FREE ( frame ) ;
2003-02-14 03:48:28 +03:00
}
2003-08-15 01:14:28 +04:00
else {
2010-07-10 03:34:34 +04:00
DEBUG ( 0 , ( " No rpc function table associated with context "
" [%d] on pipe [%s] \n " ,
pkt - > u . request . context_id ,
get_pipe_name_from_syntax ( talloc_tos ( ) ,
& p - > syntax ) ) ) ;
2000-03-10 00:45:16 +03:00
}
2005-09-30 21:13:37 +04:00
if ( changed_user ) {
2001-10-19 00:15:12 +04:00
unbecome_authenticated_pipe_user ( ) ;
2005-09-30 21:13:37 +04:00
}
2000-03-10 00:45:16 +03:00
return ret ;
1998-11-12 19:07:00 +03:00
}
2000-03-10 00:45:16 +03:00
/*******************************************************************
Calls the underlying RPC function for a named pipe .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-28 12:16:34 +04:00
static bool api_rpcTNP ( struct pipes_struct * p , struct ncacn_packet * pkt ,
2008-07-26 13:25:24 +04:00
const struct api_struct * api_rpc_cmds , int n_cmds )
2000-03-10 00:45:16 +03:00
{
int fn_num ;
2010-07-13 23:43:44 +04:00
uint32_t offset1 ;
2009-01-06 13:32:07 +03:00
2000-03-10 00:45:16 +03:00
/* interpret the command */
2009-11-08 21:37:53 +03:00
DEBUG ( 4 , ( " api_rpcTNP: %s op 0x%x - " ,
get_pipe_name_from_syntax ( talloc_tos ( ) , & p - > syntax ) ,
2010-07-10 03:34:34 +04:00
pkt - > u . request . opnum ) ) ;
2000-03-10 00:45:16 +03:00
2009-02-01 14:03:31 +03:00
if ( DEBUGLEVEL > = 50 ) {
fstring name ;
2009-11-08 21:37:53 +03:00
slprintf ( name , sizeof ( name ) - 1 , " in_%s " ,
get_pipe_name_from_syntax ( talloc_tos ( ) , & p - > syntax ) ) ;
2010-07-16 00:54:14 +04:00
dump_pdu_region ( name , pkt - > u . request . opnum ,
& p - > in_data . data , 0 ,
2010-07-15 18:28:59 +04:00
p - > in_data . data . length ) ;
2009-02-01 14:03:31 +03:00
}
2000-05-15 11:18:12 +04:00
2003-02-14 03:48:28 +03:00
for ( fn_num = 0 ; fn_num < n_cmds ; fn_num + + ) {
2010-07-10 03:34:34 +04:00
if ( api_rpc_cmds [ fn_num ] . opnum = = pkt - > u . request . opnum & &
api_rpc_cmds [ fn_num ] . fn ! = NULL ) {
DEBUG ( 3 , ( " api_rpcTNP: rpc command: %s \n " ,
api_rpc_cmds [ fn_num ] . name ) ) ;
2000-03-10 00:45:16 +03:00
break ;
}
}
2003-02-14 03:48:28 +03:00
if ( fn_num = = n_cmds ) {
2000-03-10 00:45:16 +03:00
/*
* For an unknown RPC just return a fault PDU but
* return True to allow RPC ' s on the pipe to continue
* and not put the pipe into fault state . JRA .
*/
DEBUG ( 4 , ( " unknown \n " ) ) ;
2006-03-21 03:04:05 +03:00
setup_fault_pdu ( p , NT_STATUS ( DCERPC_FAULT_OP_RNG_ERROR ) ) ;
2000-03-10 00:45:16 +03:00
return True ;
}
2010-07-13 23:43:44 +04:00
offset1 = p - > out_data . rdata . length ;
2000-05-15 13:59:58 +04:00
2003-02-14 03:48:28 +03:00
DEBUG ( 6 , ( " api_rpc_cmds[%d].fn == %p \n " ,
fn_num , api_rpc_cmds [ fn_num ] . fn ) ) ;
2000-03-10 00:45:16 +03:00
/* do the actual command */
2000-06-16 12:11:32 +04:00
if ( ! api_rpc_cmds [ fn_num ] . fn ( p ) ) {
2009-11-08 21:37:53 +03:00
DEBUG ( 0 , ( " api_rpcTNP: %s: %s failed. \n " ,
get_pipe_name_from_syntax ( talloc_tos ( ) , & p - > syntax ) ,
2009-02-01 14:03:31 +03:00
api_rpc_cmds [ fn_num ] . name ) ) ;
2010-07-13 23:43:44 +04:00
data_blob_free ( & p - > out_data . rdata ) ;
2000-03-10 00:45:16 +03:00
return False ;
}
2002-01-25 08:28:37 +03:00
if ( p - > bad_handle_fault_state ) {
DEBUG ( 4 , ( " api_rpcTNP: bad handle fault return. \n " ) ) ;
p - > bad_handle_fault_state = False ;
2006-03-21 03:04:05 +03:00
setup_fault_pdu ( p , NT_STATUS ( DCERPC_FAULT_CONTEXT_MISMATCH ) ) ;
2002-01-25 08:28:37 +03:00
return True ;
}
2006-10-10 11:53:41 +04:00
if ( p - > rng_fault_state ) {
DEBUG ( 4 , ( " api_rpcTNP: rng fault return \n " ) ) ;
p - > rng_fault_state = False ;
setup_fault_pdu ( p , NT_STATUS ( DCERPC_FAULT_OP_RNG_ERROR ) ) ;
return True ;
}
2009-02-01 14:03:31 +03:00
if ( DEBUGLEVEL > = 50 ) {
fstring name ;
2009-11-08 21:37:53 +03:00
slprintf ( name , sizeof ( name ) - 1 , " out_%s " ,
get_pipe_name_from_syntax ( talloc_tos ( ) , & p - > syntax ) ) ;
2010-07-16 00:54:14 +04:00
dump_pdu_region ( name , pkt - > u . request . opnum ,
& p - > out_data . rdata , offset1 ,
2010-07-13 23:43:44 +04:00
p - > out_data . rdata . length ) ;
2009-02-01 14:03:31 +03:00
}
2000-05-15 13:59:58 +04:00
2009-02-01 14:03:31 +03:00
DEBUG ( 5 , ( " api_rpcTNP: called %s successfully \n " ,
2009-11-08 21:37:53 +03:00
get_pipe_name_from_syntax ( talloc_tos ( ) , & p - > syntax ) ) ) ;
2000-03-10 00:45:16 +03:00
2000-10-18 05:15:05 +04:00
/* Check for buffer underflow in rpc parsing */
2010-07-15 18:28:59 +04:00
if ( ( DEBUGLEVEL > = 10 ) & &
( pkt - > frag_length < p - > in_data . data . length ) ) {
2000-10-18 05:15:05 +04:00
DEBUG ( 10 , ( " api_rpcTNP: rpc input buffer underflow (parse error?) \n " ) ) ;
2010-07-15 18:28:59 +04:00
dump_data ( 10 , p - > in_data . data . data + pkt - > frag_length ,
p - > in_data . data . length - pkt - > frag_length ) ;
2000-10-18 05:15:05 +04:00
}
2000-03-10 00:45:16 +03:00
return True ;
}
2010-07-17 23:22:26 +04:00
/****************************************************************************
Initialise an outgoing packet .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-28 12:16:34 +04:00
static bool pipe_init_outgoing_data ( struct pipes_struct * p )
2010-07-17 23:22:26 +04:00
{
output_data * o_data = & p - > out_data ;
/* Reset the offset counters. */
o_data - > data_sent_length = 0 ;
o_data - > current_pdu_sent = 0 ;
data_blob_free ( & o_data - > frag ) ;
/* Free any memory in the current return data buffer. */
data_blob_free ( & o_data - > rdata ) ;
return True ;
}
/****************************************************************************
Sets the fault state on incoming packets .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-28 12:16:34 +04:00
void set_incoming_fault ( struct pipes_struct * p )
2010-07-17 23:22:26 +04:00
{
data_blob_free ( & p - > in_data . data ) ;
p - > in_data . pdu_needed_len = 0 ;
p - > in_data . pdu . length = 0 ;
p - > fault_state = True ;
DEBUG ( 10 , ( " set_incoming_fault: Setting fault state on pipe %s \n " ,
get_pipe_name_from_syntax ( talloc_tos ( ) , & p - > syntax ) ) ) ;
}
2010-07-20 03:34:34 +04:00
static NTSTATUS dcesrv_auth_request ( struct pipe_auth_data * auth ,
struct ncacn_packet * pkt ,
DATA_BLOB * raw_pkt )
{
NTSTATUS status ;
size_t hdr_size = DCERPC_REQUEST_LENGTH ;
size_t pad_len ;
DEBUG ( 10 , ( " Checking request auth. \n " ) ) ;
if ( pkt - > pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID ) {
hdr_size + = 16 ;
}
/* in case of sealing this function will unseal the data in place */
status = dcerpc_check_auth ( auth , pkt ,
& pkt - > u . request . stub_and_verifier ,
hdr_size , raw_pkt ,
& pad_len ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/* remove padding and auth trailer,
* this way the caller will get just the data */
if ( pkt - > auth_length ) {
size_t trail_len = pad_len
+ DCERPC_AUTH_TRAILER_LENGTH
+ pkt - > auth_length ;
if ( pkt - > u . request . stub_and_verifier . length < trail_len ) {
return NT_STATUS_INFO_LENGTH_MISMATCH ;
}
pkt - > u . request . stub_and_verifier . length - = trail_len ;
2010-07-17 23:22:26 +04:00
}
2010-07-20 01:14:56 +04:00
return NT_STATUS_OK ;
2010-07-17 23:22:26 +04:00
}
/****************************************************************************
Processes a request pdu . This will do auth processing if needed , and
appends the data into the complete stream if the LAST flag is not set .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-28 12:16:34 +04:00
static bool process_request_pdu ( struct pipes_struct * p , struct ncacn_packet * pkt )
2010-07-17 23:22:26 +04:00
{
2010-07-20 01:14:56 +04:00
NTSTATUS status ;
2010-07-17 23:22:26 +04:00
DATA_BLOB data ;
if ( ! p - > pipe_bound ) {
DEBUG ( 0 , ( " process_request_pdu: rpc request with no bind. \n " ) ) ;
set_incoming_fault ( p ) ;
return False ;
}
/* Store the opnum */
p - > opnum = pkt - > u . request . opnum ;
2010-07-20 01:51:18 +04:00
status = dcesrv_auth_request ( & p - > auth , pkt , & p - > in_data . pdu ) ;
2010-07-20 01:14:56 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-07-20 03:34:34 +04:00
DEBUG ( 0 , ( " Failed to check packet auth. (%s) \n " ,
nt_errstr ( status ) ) ) ;
2010-07-17 23:22:26 +04:00
set_incoming_fault ( p ) ;
return false ;
}
data = pkt - > u . request . stub_and_verifier ;
/*
* Check the data length doesn ' t go over the 15 Mb limit .
* increased after observing a bug in the Windows NT 4.0 SP6a
* spoolsv . exe when the response to a GETPRINTERDRIVER2 RPC
* will not fit in the initial buffer of size 0x1068 - - jerry 22 / 01 / 2002
*/
if ( p - > in_data . data . length + data . length > MAX_RPC_DATA_SIZE ) {
DEBUG ( 0 , ( " process_request_pdu: "
" rpc data buffer too large (%u) + (%u) \n " ,
( unsigned int ) p - > in_data . data . length ,
( unsigned int ) data . length ) ) ;
set_incoming_fault ( p ) ;
return False ;
}
/*
* Append the data portion into the buffer and return .
*/
if ( data . length ) {
if ( ! data_blob_append ( p - > mem_ctx , & p - > in_data . data ,
data . data , data . length ) ) {
DEBUG ( 0 , ( " Unable to append data size %u "
" to parse buffer of size %u. \n " ,
( unsigned int ) data . length ,
( unsigned int ) p - > in_data . data . length ) ) ;
set_incoming_fault ( p ) ;
return False ;
}
}
if ( pkt - > pfc_flags & DCERPC_PFC_FLAG_LAST ) {
bool ret = False ;
/*
* Ok - we finally have a complete RPC stream .
* Call the rpc command to process it .
*/
/*
* Process the complete data stream here .
*/
if ( pipe_init_outgoing_data ( p ) ) {
ret = api_pipe_request ( p , pkt ) ;
}
return ret ;
}
return True ;
}
/****************************************************************************
Processes a finished PDU stored in p - > in_data . pdu .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-28 12:16:34 +04:00
void process_complete_pdu ( struct pipes_struct * p )
2010-07-17 23:22:26 +04:00
{
struct ncacn_packet * pkt = NULL ;
NTSTATUS status ;
bool reply = False ;
if ( p - > fault_state ) {
DEBUG ( 10 , ( " process_complete_pdu: pipe %s in fault state. \n " ,
get_pipe_name_from_syntax ( talloc_tos ( ) , & p - > syntax ) ) ) ;
goto done ;
}
pkt = talloc ( p - > mem_ctx , struct ncacn_packet ) ;
if ( ! pkt ) {
DEBUG ( 0 , ( " Out of memory! \n " ) ) ;
goto done ;
}
/*
* Ensure we ' re using the corrent endianness for both the
* RPC header flags and the raw data we will be reading from .
*/
if ( dcerpc_get_endian_flag ( & p - > in_data . pdu ) & DCERPC_DREP_LE ) {
p - > endian = RPC_LITTLE_ENDIAN ;
} else {
p - > endian = RPC_BIG_ENDIAN ;
}
DEBUG ( 10 , ( " PDU is in %s Endian format! \n " , p - > endian ? " Big " : " Little " ) ) ;
status = dcerpc_pull_ncacn_packet ( pkt , & p - > in_data . pdu ,
pkt , p - > endian ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Failed to unmarshal rpc packet: %s! \n " ,
nt_errstr ( status ) ) ) ;
goto done ;
}
/* Store the call_id */
p - > call_id = pkt - > call_id ;
DEBUG ( 10 , ( " Processing packet type %d \n " , ( int ) pkt - > ptype ) ) ;
switch ( pkt - > ptype ) {
case DCERPC_PKT_REQUEST :
reply = process_request_pdu ( p , pkt ) ;
break ;
case DCERPC_PKT_PING : /* CL request - ignore... */
DEBUG ( 0 , ( " process_complete_pdu: Error. "
" Connectionless packet type %d received on "
" pipe %s. \n " , ( int ) pkt - > ptype ,
get_pipe_name_from_syntax ( talloc_tos ( ) ,
& p - > syntax ) ) ) ;
break ;
case DCERPC_PKT_RESPONSE : /* No responses here. */
DEBUG ( 0 , ( " process_complete_pdu: Error. "
" DCERPC_PKT_RESPONSE received from client "
" on pipe %s. \n " ,
get_pipe_name_from_syntax ( talloc_tos ( ) ,
& p - > syntax ) ) ) ;
break ;
case DCERPC_PKT_FAULT :
case DCERPC_PKT_WORKING :
/* CL request - reply to a ping when a call in process. */
case DCERPC_PKT_NOCALL :
/* CL - server reply to a ping call. */
case DCERPC_PKT_REJECT :
case DCERPC_PKT_ACK :
case DCERPC_PKT_CL_CANCEL :
case DCERPC_PKT_FACK :
case DCERPC_PKT_CANCEL_ACK :
DEBUG ( 0 , ( " process_complete_pdu: Error. "
" Connectionless packet type %u received on "
" pipe %s. \n " , ( unsigned int ) pkt - > ptype ,
get_pipe_name_from_syntax ( talloc_tos ( ) ,
& p - > syntax ) ) ) ;
break ;
case DCERPC_PKT_BIND :
/*
* We assume that a pipe bind is only in one pdu .
*/
if ( pipe_init_outgoing_data ( p ) ) {
reply = api_pipe_bind_req ( p , pkt ) ;
}
break ;
case DCERPC_PKT_BIND_ACK :
case DCERPC_PKT_BIND_NAK :
DEBUG ( 0 , ( " process_complete_pdu: Error. "
" DCERPC_PKT_BINDACK/DCERPC_PKT_BINDNACK "
" packet type %u received on pipe %s. \n " ,
( unsigned int ) pkt - > ptype ,
get_pipe_name_from_syntax ( talloc_tos ( ) ,
& p - > syntax ) ) ) ;
break ;
case DCERPC_PKT_ALTER :
/*
* We assume that a pipe bind is only in one pdu .
*/
if ( pipe_init_outgoing_data ( p ) ) {
reply = api_pipe_alter_context ( p , pkt ) ;
}
break ;
case DCERPC_PKT_ALTER_RESP :
DEBUG ( 0 , ( " process_complete_pdu: Error. "
" DCERPC_PKT_ALTER_RESP on pipe %s: "
" Should only be server -> client. \n " ,
get_pipe_name_from_syntax ( talloc_tos ( ) ,
& p - > syntax ) ) ) ;
break ;
case DCERPC_PKT_AUTH3 :
/*
2010-08-27 23:23:20 +04:00
* The third packet in an auth exchange .
2010-07-17 23:22:26 +04:00
*/
if ( pipe_init_outgoing_data ( p ) ) {
reply = api_pipe_bind_auth3 ( p , pkt ) ;
}
break ;
case DCERPC_PKT_SHUTDOWN :
DEBUG ( 0 , ( " process_complete_pdu: Error. "
" DCERPC_PKT_SHUTDOWN on pipe %s: "
" Should only be server -> client. \n " ,
get_pipe_name_from_syntax ( talloc_tos ( ) ,
& p - > syntax ) ) ) ;
break ;
case DCERPC_PKT_CO_CANCEL :
/* For now just free all client data and continue
* processing . */
DEBUG ( 3 , ( " process_complete_pdu: DCERPC_PKT_CO_CANCEL. "
" Abandoning rpc call. \n " ) ) ;
/* As we never do asynchronous RPC serving, we can
* never cancel a call ( as far as I know ) .
* If we ever did we ' d have to send a cancel_ack reply .
* For now , just free all client data and continue
* processing . */
reply = True ;
break ;
#if 0
/* Enable this if we're doing async rpc. */
/* We must check the outstanding callid matches. */
if ( pipe_init_outgoing_data ( p ) ) {
/* Send a cancel_ack PDU reply. */
/* We should probably check the auth-verifier here. */
reply = setup_cancel_ack_reply ( p , pkt ) ;
}
break ;
# endif
case DCERPC_PKT_ORPHANED :
/* We should probably check the auth-verifier here.
* For now just free all client data and continue
* processing . */
DEBUG ( 3 , ( " process_complete_pdu: DCERPC_PKT_ORPHANED. "
" Abandoning rpc call. \n " ) ) ;
reply = True ;
break ;
default :
DEBUG ( 0 , ( " process_complete_pdu: "
" Unknown rpc type = %u received. \n " ,
( unsigned int ) pkt - > ptype ) ) ;
break ;
}
done :
if ( ! reply ) {
DEBUG ( 3 , ( " process_complete_pdu: DCE/RPC fault sent on "
" pipe %s \n " , get_pipe_name_from_syntax ( talloc_tos ( ) ,
& p - > syntax ) ) ) ;
set_incoming_fault ( p ) ;
setup_fault_pdu ( p , NT_STATUS ( DCERPC_FAULT_OP_RNG_ERROR ) ) ;
TALLOC_FREE ( pkt ) ;
} else {
/*
* Reset the lengths . We ' re ready for a new pdu .
*/
TALLOC_FREE ( p - > in_data . pdu . data ) ;
p - > in_data . pdu_needed_len = 0 ;
p - > in_data . pdu . length = 0 ;
}
TALLOC_FREE ( pkt ) ;
}