2010-08-02 17:47:01 +04:00
/*
2002-01-30 09:08:46 +03:00
* Unix SMB / CIFS implementation .
2010-08-02 17:47:01 +04:00
* RPC Pipe client routines
2005-09-30 21:13:37 +04:00
* Largely rewritten by Jeremy Allison 2005.
2010-08-02 17:47:01 +04:00
* Heavily modified by Simo Sorce 2010.
2011-12-27 03:25:55 +04:00
* Copyright Andrew Bartlett 2011.
2010-08-02 17:47:01 +04:00
*
1998-03-12 00:11:04 +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-03-12 00:11:04 +03:00
* ( at your option ) any later version .
2010-08-02 17:47:01 +04:00
*
1998-03-12 00:11:04 +03:00
* 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 .
2010-08-02 17:47:01 +04:00
*
1998-03-12 00:11:04 +03:00
* 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-03-12 00:11:04 +03:00
*/
# include "includes.h"
2011-04-28 19:38:09 +04:00
# include "../lib/util/tevent_ntstatus.h"
2011-01-28 12:31:39 +03:00
# include "librpc/gen_ndr/ndr_epmapper_c.h"
2010-05-05 03:39:16 +04:00
# include "../librpc/gen_ndr/ndr_dssetup.h"
2009-09-16 02:26:17 +04:00
# include "../libcli/auth/schannel.h"
2013-07-27 13:30:13 +04:00
# include "../libcli/auth/netlogon_creds_cli.h"
2011-12-27 03:25:55 +04:00
# include "auth_generic.h"
2009-03-23 13:04:34 +03:00
# include "librpc/gen_ndr/ndr_dcerpc.h"
2012-01-02 21:54:47 +04:00
# include "librpc/gen_ndr/ndr_netlogon_c.h"
2010-07-14 20:18:49 +04:00
# include "librpc/rpc/dcerpc.h"
2010-08-18 20:26:17 +04:00
# include "rpc_dce.h"
2011-02-28 12:19:44 +03:00
# include "cli_pipe.h"
2011-07-22 18:44:02 +04:00
# include "libsmb/libsmb.h"
2011-10-18 14:13:16 +04:00
# include "auth/gensec/gensec.h"
2012-02-06 05:40:38 +04:00
# include "auth/credentials/credentials.h"
2012-05-19 19:31:50 +04:00
# include "../libcli/smb/smbXcli_base.h"
1998-03-12 00:11:04 +03:00
2002-07-15 14:35:28 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_RPC_CLI
2008-04-24 22:24:37 +04:00
/********************************************************************
Pipe description for a DEBUG
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-01-22 20:52:15 +03:00
static const char * rpccli_pipe_txt ( TALLOC_CTX * mem_ctx ,
struct rpc_pipe_client * cli )
2008-04-24 22:24:37 +04:00
{
2009-01-22 20:52:15 +03:00
char * result = talloc_asprintf ( mem_ctx , " host %s " , cli - > desthost ) ;
if ( result = = NULL ) {
return " pipe " ;
2008-05-13 01:37:07 +04:00
}
2008-04-24 22:24:37 +04:00
return result ;
}
1998-03-12 00:11:04 +03:00
/********************************************************************
1999-12-13 16:27:58 +03:00
Rpc pipe call id .
1998-03-12 00:11:04 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
1998-09-05 09:07:05 +04:00
static uint32 get_rpc_call_id ( void )
1998-03-12 00:11:04 +03:00
{
1999-12-13 16:27:58 +03:00
static uint32 call_id = 0 ;
return + + call_id ;
1998-03-12 00:11:04 +03:00
}
/*******************************************************************
1999-12-13 16:27:58 +03:00
Use SMBreadX to get rest of one fragment ' s worth of rpc data .
2009-01-14 18:06:10 +03:00
Reads the whole size or give an error message
1998-03-12 00:11:04 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-04-24 02:45:53 +04:00
2009-01-15 23:56:03 +03:00
struct rpc_read_state {
2013-02-18 12:57:22 +04:00
struct tevent_context * ev ;
2009-01-22 20:52:15 +03:00
struct rpc_cli_transport * transport ;
uint8_t * data ;
2009-01-15 23:56:03 +03:00
size_t size ;
size_t num_read ;
} ;
2009-03-24 01:03:37 +03:00
static void rpc_read_done ( struct tevent_req * subreq ) ;
2009-01-15 23:56:03 +03:00
2009-03-23 23:37:27 +03:00
static struct tevent_req * rpc_read_send ( TALLOC_CTX * mem_ctx ,
2013-02-18 12:57:22 +04:00
struct tevent_context * ev ,
2009-03-23 23:37:27 +03:00
struct rpc_cli_transport * transport ,
uint8_t * data , size_t size )
1998-03-12 00:11:04 +03:00
{
2009-03-24 01:03:37 +03:00
struct tevent_req * req , * subreq ;
2009-01-15 23:56:03 +03:00
struct rpc_read_state * state ;
1998-03-12 00:11:04 +03:00
2009-03-23 23:37:27 +03:00
req = tevent_req_create ( mem_ctx , & state , struct rpc_read_state ) ;
if ( req = = NULL ) {
2009-01-15 23:56:03 +03:00
return NULL ;
}
state - > ev = ev ;
2009-01-22 20:52:15 +03:00
state - > transport = transport ;
2009-01-15 23:56:03 +03:00
state - > data = data ;
state - > size = size ;
state - > num_read = 0 ;
DEBUG ( 5 , ( " rpc_read_send: data_to_read: %u \n " , ( unsigned int ) size ) ) ;
2009-01-22 20:52:15 +03:00
subreq = transport - > read_send ( state , ev , ( uint8_t * ) data , size ,
transport - > priv ) ;
if ( subreq = = NULL ) {
goto fail ;
2009-01-15 23:56:03 +03:00
}
2009-03-24 01:03:37 +03:00
tevent_req_set_callback ( subreq , rpc_read_done , req ) ;
2009-03-23 23:37:27 +03:00
return req ;
2009-01-15 23:56:03 +03:00
fail :
2009-03-23 23:37:27 +03:00
TALLOC_FREE ( req ) ;
2009-01-15 23:56:03 +03:00
return NULL ;
}
2009-01-14 18:43:37 +03:00
2009-03-24 01:03:37 +03:00
static void rpc_read_done ( struct tevent_req * subreq )
2009-01-15 23:56:03 +03:00
{
2009-03-24 01:03:37 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2009-03-23 23:37:27 +03:00
struct rpc_read_state * state = tevent_req_data (
req , struct rpc_read_state ) ;
2009-01-15 23:56:03 +03:00
NTSTATUS status ;
ssize_t received ;
2009-01-22 20:52:15 +03:00
status = state - > transport - > read_recv ( subreq , & received ) ;
TALLOC_FREE ( subreq ) ;
2009-01-15 23:56:03 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-03-23 23:37:27 +03:00
tevent_req_nterror ( req , status ) ;
2009-01-15 23:56:03 +03:00
return ;
}
state - > num_read + = received ;
if ( state - > num_read = = state - > size ) {
2009-03-23 23:37:27 +03:00
tevent_req_done ( req ) ;
2009-01-15 23:56:03 +03:00
return ;
}
2009-01-22 20:52:15 +03:00
subreq = state - > transport - > read_send ( state , state - > ev ,
state - > data + state - > num_read ,
state - > size - state - > num_read ,
state - > transport - > priv ) ;
2009-03-23 23:37:27 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
2009-01-15 23:56:03 +03:00
return ;
}
2009-03-24 01:03:37 +03:00
tevent_req_set_callback ( subreq , rpc_read_done , req ) ;
2009-01-15 23:56:03 +03:00
}
2009-03-23 23:37:27 +03:00
static NTSTATUS rpc_read_recv ( struct tevent_req * req )
2009-01-15 23:56:03 +03:00
{
2009-03-23 23:37:27 +03:00
return tevent_req_simple_recv_ntstatus ( req ) ;
2009-01-15 23:56:03 +03:00
}
2009-01-17 17:07:52 +03:00
struct rpc_write_state {
2013-02-18 12:57:22 +04:00
struct tevent_context * ev ;
2009-01-22 20:52:15 +03:00
struct rpc_cli_transport * transport ;
const uint8_t * data ;
2009-01-17 17:07:52 +03:00
size_t size ;
size_t num_written ;
} ;
2009-03-24 01:20:03 +03:00
static void rpc_write_done ( struct tevent_req * subreq ) ;
2009-01-17 17:07:52 +03:00
2009-03-23 23:49:19 +03:00
static struct tevent_req * rpc_write_send ( TALLOC_CTX * mem_ctx ,
2013-02-18 12:57:22 +04:00
struct tevent_context * ev ,
2009-03-23 23:49:19 +03:00
struct rpc_cli_transport * transport ,
const uint8_t * data , size_t size )
2009-01-17 17:07:52 +03:00
{
2009-03-24 01:20:03 +03:00
struct tevent_req * req , * subreq ;
2009-01-17 17:07:52 +03:00
struct rpc_write_state * state ;
2009-03-23 23:49:19 +03:00
req = tevent_req_create ( mem_ctx , & state , struct rpc_write_state ) ;
if ( req = = NULL ) {
2009-01-17 17:07:52 +03:00
return NULL ;
}
state - > ev = ev ;
2009-01-22 20:52:15 +03:00
state - > transport = transport ;
2009-01-17 17:07:52 +03:00
state - > data = data ;
state - > size = size ;
state - > num_written = 0 ;
DEBUG ( 5 , ( " rpc_write_send: data_to_write: %u \n " , ( unsigned int ) size ) ) ;
2009-01-22 20:52:15 +03:00
subreq = transport - > write_send ( state , ev , data , size , transport - > priv ) ;
if ( subreq = = NULL ) {
goto fail ;
2009-01-17 17:07:52 +03:00
}
2009-03-24 01:20:03 +03:00
tevent_req_set_callback ( subreq , rpc_write_done , req ) ;
2009-03-23 23:49:19 +03:00
return req ;
2009-01-17 17:07:52 +03:00
fail :
2009-03-23 23:49:19 +03:00
TALLOC_FREE ( req ) ;
2009-01-17 17:07:52 +03:00
return NULL ;
}
2009-03-24 01:20:03 +03:00
static void rpc_write_done ( struct tevent_req * subreq )
2009-01-17 17:07:52 +03:00
{
2009-03-24 01:20:03 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2009-03-23 23:49:19 +03:00
struct rpc_write_state * state = tevent_req_data (
req , struct rpc_write_state ) ;
2009-01-17 17:07:52 +03:00
NTSTATUS status ;
2009-01-22 20:52:15 +03:00
ssize_t written ;
2009-01-17 17:07:52 +03:00
2009-01-22 20:52:15 +03:00
status = state - > transport - > write_recv ( subreq , & written ) ;
2009-01-17 17:07:52 +03:00
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-03-23 23:49:19 +03:00
tevent_req_nterror ( req , status ) ;
2009-01-17 17:07:52 +03:00
return ;
}
state - > num_written + = written ;
if ( state - > num_written = = state - > size ) {
2009-03-23 23:49:19 +03:00
tevent_req_done ( req ) ;
2009-01-17 17:07:52 +03:00
return ;
}
2009-01-22 20:52:15 +03:00
subreq = state - > transport - > write_send ( state , state - > ev ,
state - > data + state - > num_written ,
state - > size - state - > num_written ,
state - > transport - > priv ) ;
2009-03-23 23:49:19 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
2009-01-17 17:07:52 +03:00
return ;
}
2009-03-24 01:20:03 +03:00
tevent_req_set_callback ( subreq , rpc_write_done , req ) ;
2009-01-17 17:07:52 +03:00
}
2009-03-23 23:49:19 +03:00
static NTSTATUS rpc_write_recv ( struct tevent_req * req )
2009-01-17 17:07:52 +03:00
{
2009-03-23 23:49:19 +03:00
return tevent_req_simple_recv_ntstatus ( req ) ;
2009-01-17 17:07:52 +03:00
}
1998-03-12 00:11:04 +03:00
/****************************************************************************
2005-09-30 21:13:37 +04:00
Try and get a PDU ' s worth of data from current_pdu . If not , then read more
from the wire .
1998-03-12 00:11:04 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2009-01-17 14:50:02 +03:00
struct get_complete_frag_state {
2013-02-18 12:57:22 +04:00
struct tevent_context * ev ;
2009-01-16 16:46:41 +03:00
struct rpc_pipe_client * cli ;
2010-07-12 17:36:39 +04:00
uint16_t frag_len ;
2010-07-15 02:29:32 +04:00
DATA_BLOB * pdu ;
2009-01-16 16:46:41 +03:00
} ;
2009-03-23 23:37:27 +03:00
static void get_complete_frag_got_header ( struct tevent_req * subreq ) ;
static void get_complete_frag_got_rest ( struct tevent_req * subreq ) ;
2009-01-16 16:46:41 +03:00
2009-03-23 23:57:19 +03:00
static struct tevent_req * get_complete_frag_send ( TALLOC_CTX * mem_ctx ,
2013-02-18 12:57:22 +04:00
struct tevent_context * ev ,
2009-03-23 23:57:19 +03:00
struct rpc_pipe_client * cli ,
2010-07-15 02:29:32 +04:00
DATA_BLOB * pdu )
1998-03-12 00:11:04 +03:00
{
2009-03-23 23:57:19 +03:00
struct tevent_req * req , * subreq ;
2009-01-17 14:50:02 +03:00
struct get_complete_frag_state * state ;
2010-07-15 02:29:32 +04:00
size_t received ;
2009-01-16 16:46:41 +03:00
NTSTATUS status ;
2005-09-30 21:13:37 +04:00
2009-03-23 23:57:19 +03:00
req = tevent_req_create ( mem_ctx , & state ,
struct get_complete_frag_state ) ;
if ( req = = NULL ) {
2009-01-16 16:46:41 +03:00
return NULL ;
2005-09-30 21:13:37 +04:00
}
2009-01-16 16:46:41 +03:00
state - > ev = ev ;
state - > cli = cli ;
2010-07-12 17:36:39 +04:00
state - > frag_len = RPC_HEADER_LEN ;
2009-01-16 16:46:41 +03:00
state - > pdu = pdu ;
2010-07-15 02:29:32 +04:00
received = pdu - > length ;
if ( received < RPC_HEADER_LEN ) {
if ( ! data_blob_realloc ( mem_ctx , pdu , RPC_HEADER_LEN ) ) {
2009-01-16 16:46:41 +03:00
status = NT_STATUS_NO_MEMORY ;
goto post_status ;
}
2010-07-15 02:29:32 +04:00
subreq = rpc_read_send ( state , state - > ev ,
state - > cli - > transport ,
pdu - > data + received ,
RPC_HEADER_LEN - received ) ;
2009-01-16 16:46:41 +03:00
if ( subreq = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto post_status ;
}
2009-03-23 23:37:27 +03:00
tevent_req_set_callback ( subreq , get_complete_frag_got_header ,
2009-03-23 23:57:19 +03:00
req ) ;
return req ;
Makefile.in :
- added srvsvc client files
clientgen.c :
- replaced cli_error(cli, int *cls, int *err) with
cli_error(cli, uint8 cls, uint32 *err). this version detects
32 bit status messages. the DOS error "MORE_DATA", the
equivalent of the 32 bit *warning* 0x8000 0005
(STATUS_BUFFER_OVERFLOW), was being processed as an error,
terminating the cli_receive_trans() call.
cli_pipe.c :
- replaced calls that had been incorrectly modified from
32 bit warnings (0x8000 0005 - STATUS_BUFFER_OVERFLOW)
to 8 bit DOS errors (0x01 0xEA - MORE_DATA).
the use of the old version of cli_error (DOS only)
instead of the new one (DOS and 32 bit) caused the
dce/rpc client code to fail.
- replaced 2 space indentation with tab indentation in all functions.
cli_srvsvc.c :
cmd_srvsvc.c :
- added these files back in, fixing them up to use jeremy's
modified versions of the dce/rpc client functions.
parse_srv.c :
- added back in some "unused" functions required by dce/rpc
client-side code. it would be helpful if all such "unused"
functions could be added back in.
rpcclient.c :
- added "session", "file", "share", "connection" enumeration
functions back in. these are equivalent to nt's "NetXXXXXEnum"
Win32 (MSDN) functions.
- added "srvinfo" function back in. this is equivalent to
nt's NetServerGetInfo Win32 (MSDN) function.
(This used to be commit bcf39ffdcc64e049bca2d70a394a99976291e81d)
1998-10-03 01:09:23 +04:00
}
1998-03-12 00:11:04 +03:00
2010-07-15 02:29:32 +04:00
state - > frag_len = dcerpc_get_frag_length ( pdu ) ;
2013-09-26 01:25:12 +04:00
if ( state - > frag_len < RPC_HEADER_LEN ) {
tevent_req_nterror ( req , NT_STATUS_RPC_PROTOCOL_ERROR ) ;
return tevent_req_post ( req , ev ) ;
}
2009-01-14 14:58:13 +03:00
2009-01-16 16:46:41 +03:00
/*
* Ensure we have frag_len bytes of data .
*/
2010-07-15 02:29:32 +04:00
if ( received < state - > frag_len ) {
if ( ! data_blob_realloc ( NULL , pdu , state - > frag_len ) ) {
2009-01-16 16:46:41 +03:00
status = NT_STATUS_NO_MEMORY ;
goto post_status ;
2009-01-14 00:50:43 +03:00
}
2009-01-22 20:52:15 +03:00
subreq = rpc_read_send ( state , state - > ev ,
2010-07-15 02:29:32 +04:00
state - > cli - > transport ,
pdu - > data + received ,
state - > frag_len - received ) ;
2009-01-16 16:46:41 +03:00
if ( subreq = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto post_status ;
2005-09-30 21:13:37 +04:00
}
2009-03-23 23:37:27 +03:00
tevent_req_set_callback ( subreq , get_complete_frag_got_rest ,
2009-03-23 23:57:19 +03:00
req ) ;
return req ;
1999-12-13 16:27:58 +03:00
}
1998-04-21 06:36:37 +04:00
2009-01-16 16:46:41 +03:00
status = NT_STATUS_OK ;
post_status :
2009-03-23 23:57:19 +03:00
if ( NT_STATUS_IS_OK ( status ) ) {
tevent_req_done ( req ) ;
} else {
tevent_req_nterror ( req , status ) ;
2009-01-16 16:46:41 +03:00
}
2009-03-23 23:57:19 +03:00
return tevent_req_post ( req , ev ) ;
2009-01-16 16:46:41 +03:00
}
2009-03-23 23:37:27 +03:00
static void get_complete_frag_got_header ( struct tevent_req * subreq )
2009-01-16 16:46:41 +03:00
{
2009-03-23 23:57:19 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct get_complete_frag_state * state = tevent_req_data (
req , struct get_complete_frag_state ) ;
2009-01-16 16:46:41 +03:00
NTSTATUS status ;
status = rpc_read_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-03-23 23:57:19 +03:00
tevent_req_nterror ( req , status ) ;
2009-01-16 16:46:41 +03:00
return ;
}
2010-07-15 02:29:32 +04:00
state - > frag_len = dcerpc_get_frag_length ( state - > pdu ) ;
2013-09-26 01:25:12 +04:00
if ( state - > frag_len < RPC_HEADER_LEN ) {
tevent_req_nterror ( req , NT_STATUS_RPC_PROTOCOL_ERROR ) ;
return ;
}
2009-01-16 16:46:41 +03:00
2010-07-15 02:29:32 +04:00
if ( ! data_blob_realloc ( NULL , state - > pdu , state - > frag_len ) ) {
2009-03-23 23:57:19 +03:00
tevent_req_nterror ( req , NT_STATUS_NO_MEMORY ) ;
2009-01-16 16:46:41 +03:00
return ;
}
/*
* We ' re here in this piece of code because we ' ve read exactly
* RPC_HEADER_LEN bytes into state - > pdu .
*/
2010-07-15 02:29:32 +04:00
subreq = rpc_read_send ( state , state - > ev , state - > cli - > transport ,
state - > pdu - > data + RPC_HEADER_LEN ,
state - > frag_len - RPC_HEADER_LEN ) ;
2009-03-23 23:57:19 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
2009-01-16 16:46:41 +03:00
return ;
}
2009-03-23 23:37:27 +03:00
tevent_req_set_callback ( subreq , get_complete_frag_got_rest , req ) ;
2009-01-16 16:46:41 +03:00
}
2009-03-23 23:37:27 +03:00
static void get_complete_frag_got_rest ( struct tevent_req * subreq )
2009-01-16 16:46:41 +03:00
{
2009-03-23 23:57:19 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2009-01-16 16:46:41 +03:00
NTSTATUS status ;
status = rpc_read_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-03-23 23:57:19 +03:00
tevent_req_nterror ( req , status ) ;
2009-01-16 16:46:41 +03:00
return ;
}
2009-03-23 23:57:19 +03:00
tevent_req_done ( req ) ;
2009-01-16 16:46:41 +03:00
}
2009-03-23 23:57:19 +03:00
static NTSTATUS get_complete_frag_recv ( struct tevent_req * req )
2009-01-16 16:46:41 +03:00
{
2009-03-23 23:57:19 +03:00
return tevent_req_simple_recv_ntstatus ( req ) ;
2009-01-16 16:46:41 +03:00
}
2005-09-30 21:13:37 +04:00
/****************************************************************************
Do basic authentication checks on an incoming pdu .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-15 03:39:54 +04:00
static NTSTATUS cli_pipe_validate_current_pdu ( TALLOC_CTX * mem_ctx ,
struct rpc_pipe_client * cli ,
struct ncacn_packet * pkt ,
DATA_BLOB * pdu ,
uint8_t expected_pkt_type ,
2013-10-18 01:44:35 +04:00
uint32_t call_id ,
2010-07-15 03:39:54 +04:00
DATA_BLOB * rdata ,
DATA_BLOB * reply_pdu )
2005-09-30 21:13:37 +04:00
{
2010-08-02 18:03:04 +04:00
struct dcerpc_response * r ;
2005-09-30 21:13:37 +04:00
NTSTATUS ret = NT_STATUS_OK ;
2010-07-20 04:03:08 +04:00
size_t pad_len = 0 ;
2005-09-30 21:13:37 +04:00
/*
* Point the return values at the real data including the RPC
* header . Just in case the caller wants it .
*/
2010-07-15 02:29:32 +04:00
* rdata = * pdu ;
2003-04-09 19:54:17 +04:00
2005-09-30 21:13:37 +04:00
/* Ensure we have the correct type. */
2010-07-13 15:59:12 +04:00
switch ( pkt - > ptype ) {
2010-07-14 22:01:44 +04:00
case DCERPC_PKT_ALTER_RESP :
case DCERPC_PKT_BIND_ACK :
2005-09-30 21:13:37 +04:00
2010-08-02 18:03:04 +04:00
/* Client code never receives this kind of packets */
2010-07-14 22:01:44 +04:00
break ;
2003-04-09 19:54:17 +04:00
2005-09-30 21:13:37 +04:00
2010-07-14 22:01:44 +04:00
case DCERPC_PKT_RESPONSE :
2005-09-30 21:13:37 +04:00
2010-08-02 18:03:04 +04:00
r = & pkt - > u . response ;
2010-07-14 22:01:44 +04:00
/* Here's where we deal with incoming sign/seal. */
2010-07-20 04:03:08 +04:00
ret = dcerpc_check_auth ( cli - > auth , pkt ,
2010-08-02 18:03:04 +04:00
& r - > stub_and_verifier ,
2010-07-20 04:03:08 +04:00
DCERPC_RESPONSE_LENGTH ,
pdu , & pad_len ) ;
2010-07-14 22:01:44 +04:00
if ( ! NT_STATUS_IS_OK ( ret ) ) {
return ret ;
}
2005-09-30 21:13:37 +04:00
2010-08-02 18:03:04 +04:00
if ( pkt - > frag_length < DCERPC_RESPONSE_LENGTH + pad_len ) {
2010-07-14 22:01:44 +04:00
return NT_STATUS_BUFFER_TOO_SMALL ;
}
2005-09-30 21:13:37 +04:00
2010-07-20 04:03:08 +04:00
/* Point the return values at the NDR data. */
2010-08-02 18:03:04 +04:00
rdata - > data = r - > stub_and_verifier . data ;
2005-09-30 21:13:37 +04:00
2010-07-14 22:01:44 +04:00
if ( pkt - > auth_length ) {
2010-07-20 04:03:08 +04:00
/* We've already done integer wrap tests in
* dcerpc_check_auth ( ) . */
2010-08-02 18:03:04 +04:00
rdata - > length = r - > stub_and_verifier . length
2010-07-20 04:03:08 +04:00
- pad_len
- DCERPC_AUTH_TRAILER_LENGTH
- pkt - > auth_length ;
} else {
2010-08-02 18:03:04 +04:00
rdata - > length = r - > stub_and_verifier . length ;
2010-07-14 22:01:44 +04:00
}
2005-09-30 21:13:37 +04:00
2010-07-15 02:29:32 +04:00
DEBUG ( 10 , ( " Got pdu len %lu, data_len %lu, ss_len %u \n " ,
2010-07-17 19:20:03 +04:00
( long unsigned int ) pdu - > length ,
( long unsigned int ) rdata - > length ,
2010-07-20 04:03:08 +04:00
( unsigned int ) pad_len ) ) ;
2010-07-14 22:01:44 +04:00
/*
* If this is the first reply , and the allocation hint is
2010-07-15 03:39:54 +04:00
* reasonable , try and set up the reply_pdu DATA_BLOB to the
* correct size .
2010-07-14 22:01:44 +04:00
*/
2010-07-15 03:39:54 +04:00
if ( ( reply_pdu - > length = = 0 ) & &
2010-08-02 18:03:04 +04:00
r - > alloc_hint & & ( r - > alloc_hint < 15 * 1024 * 1024 ) ) {
2010-07-15 03:39:54 +04:00
if ( ! data_blob_realloc ( mem_ctx , reply_pdu ,
2010-08-02 18:03:04 +04:00
r - > alloc_hint ) ) {
2010-07-14 22:01:44 +04:00
DEBUG ( 0 , ( " reply alloc hint %d too "
" large to allocate \n " ,
2010-08-02 18:03:04 +04:00
( int ) r - > alloc_hint ) ) ;
2010-07-14 22:01:44 +04:00
return NT_STATUS_NO_MEMORY ;
2005-09-30 21:13:37 +04:00
}
2004-05-14 00:32:21 +04:00
}
2010-07-14 22:01:44 +04:00
break ;
case DCERPC_PKT_BIND_NAK :
2010-08-02 18:14:02 +04:00
DEBUG ( 1 , ( __location__ " : Bind NACK received from %s! \n " ,
2010-07-14 22:01:44 +04:00
rpccli_pipe_txt ( talloc_tos ( ) , cli ) ) ) ;
/* Use this for now... */
return NT_STATUS_NETWORK_ACCESS_DENIED ;
case DCERPC_PKT_FAULT :
2010-08-02 18:14:02 +04:00
DEBUG ( 1 , ( __location__ " : RPC fault code %s received "
" from %s! \n " ,
2010-07-14 22:01:44 +04:00
dcerpc_errstr ( talloc_tos ( ) ,
pkt - > u . fault . status ) ,
2010-08-02 18:03:04 +04:00
rpccli_pipe_txt ( talloc_tos ( ) , cli ) ) ) ;
2010-07-14 22:01:44 +04:00
2011-04-24 02:00:40 +04:00
return dcerpc_fault_to_nt_status ( pkt - > u . fault . status ) ;
Jeremy requested that I get my NTLMSSP patch into CVS. He didn't request
the schannel code, but I've included that anyway. :-)
This patch revives the client-side NTLMSSP support for RPC named pipes
in Samba, and cleans up the client and server schannel code. The use of the
new code is enabled by the 'sign', 'seal' and 'schannel' commands in
rpcclient.
The aim was to prove that our separate NTLMSSP client library actually
implements NTLMSSP signing and sealing as per Microsoft's NTLMv1 implementation,
in the hope that knowing this will assist us in correctly implementing
NTLMSSP signing for SMB packets. (Still not yet functional)
This patch replaces the NTLMSSP implementation in rpc_client/cli_pipe.c with
calls to libsmb/ntlmssp.c. In the process, we have gained the ability to
use the more secure NT password, and the ability to sign-only, instead of
having to seal the pipe connection. (Previously we were limited to sealing,
and could only use the LM-password derived key).
Our new client-side NTLMSSP code also needed alteration to cope with our
comparatively simple server-side implementation. A future step is to replace
it with calls to the same NTLMSSP library.
Also included in this patch is the schannel 'sign only' patch I submitted to
the team earlier. While not enabled (and not functional, at this stage) the
work in this patch makes the code paths *much* easier to follow. I have also
included similar hooks in rpccleint to allow the use of schannel on *any* pipe.
rpcclient now defaults to not using schannel (or any other extra per-pipe
authenticiation) for any connection. The 'schannel' command enables schannel
for all pipes until disabled.
This code is also much more secure than the previous code, as changes to our
cli_pipe routines ensure that the authentication footer cannot be removed
by an attacker, and more error states are correctly handled.
(The same needs to be done to our server)
Andrew Bartlett
(This used to be commit 5472ddc9eaf4e79c5b2e1c8ee8c7f190dc285f19)
2003-07-14 12:46:32 +04:00
2010-07-14 22:01:44 +04:00
default :
2010-08-02 18:14:02 +04:00
DEBUG ( 0 , ( __location__ " Unknown packet type %u received "
" from %s! \n " ,
2010-08-02 18:03:04 +04:00
( unsigned int ) pkt - > ptype ,
rpccli_pipe_txt ( talloc_tos ( ) , cli ) ) ) ;
2013-10-18 01:44:35 +04:00
return NT_STATUS_RPC_PROTOCOL_ERROR ;
2005-09-30 21:13:37 +04:00
}
Jeremy requested that I get my NTLMSSP patch into CVS. He didn't request
the schannel code, but I've included that anyway. :-)
This patch revives the client-side NTLMSSP support for RPC named pipes
in Samba, and cleans up the client and server schannel code. The use of the
new code is enabled by the 'sign', 'seal' and 'schannel' commands in
rpcclient.
The aim was to prove that our separate NTLMSSP client library actually
implements NTLMSSP signing and sealing as per Microsoft's NTLMv1 implementation,
in the hope that knowing this will assist us in correctly implementing
NTLMSSP signing for SMB packets. (Still not yet functional)
This patch replaces the NTLMSSP implementation in rpc_client/cli_pipe.c with
calls to libsmb/ntlmssp.c. In the process, we have gained the ability to
use the more secure NT password, and the ability to sign-only, instead of
having to seal the pipe connection. (Previously we were limited to sealing,
and could only use the LM-password derived key).
Our new client-side NTLMSSP code also needed alteration to cope with our
comparatively simple server-side implementation. A future step is to replace
it with calls to the same NTLMSSP library.
Also included in this patch is the schannel 'sign only' patch I submitted to
the team earlier. While not enabled (and not functional, at this stage) the
work in this patch makes the code paths *much* easier to follow. I have also
included similar hooks in rpccleint to allow the use of schannel on *any* pipe.
rpcclient now defaults to not using schannel (or any other extra per-pipe
authenticiation) for any connection. The 'schannel' command enables schannel
for all pipes until disabled.
This code is also much more secure than the previous code, as changes to our
cli_pipe routines ensure that the authentication footer cannot be removed
by an attacker, and more error states are correctly handled.
(The same needs to be done to our server)
Andrew Bartlett
(This used to be commit 5472ddc9eaf4e79c5b2e1c8ee8c7f190dc285f19)
2003-07-14 12:46:32 +04:00
2010-07-13 15:59:12 +04:00
if ( pkt - > ptype ! = expected_pkt_type ) {
2010-08-02 18:14:02 +04:00
DEBUG ( 3 , ( __location__ " : Connection to %s got an unexpected "
" RPC packet type - %u, not %u \n " ,
2010-08-02 18:03:04 +04:00
rpccli_pipe_txt ( talloc_tos ( ) , cli ) ,
2010-08-02 18:14:02 +04:00
pkt - > ptype , expected_pkt_type ) ) ;
2013-10-18 01:44:35 +04:00
return NT_STATUS_RPC_PROTOCOL_ERROR ;
}
if ( pkt - > call_id ! = call_id ) {
DEBUG ( 3 , ( __location__ " : Connection to %s got an unexpected "
" RPC call_id - %u, not %u \n " ,
rpccli_pipe_txt ( talloc_tos ( ) , cli ) ,
pkt - > call_id , call_id ) ) ;
return NT_STATUS_RPC_PROTOCOL_ERROR ;
2003-04-09 19:54:17 +04:00
}
2005-09-30 21:13:37 +04:00
/* Do this just before return - we don't want to modify any rpc header
data before now as we may have needed to do cryptographic actions on
it before . */
2010-07-13 15:59:12 +04:00
if ( ( pkt - > ptype = = DCERPC_PKT_BIND_ACK ) & &
! ( pkt - > pfc_flags & DCERPC_PFC_FLAG_LAST ) ) {
2010-08-02 18:14:02 +04:00
DEBUG ( 5 , ( __location__ " : bug in server (AS/U?), setting "
" fragment first/last ON. \n " ) ) ;
pkt - > pfc_flags | = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST ;
2005-09-30 21:13:37 +04:00
}
return NT_STATUS_OK ;
1998-10-14 10:29:20 +04:00
}
2009-01-11 13:17:26 +03:00
/****************************************************************************
Call a remote api on an arbitrary pipe . takes param , data and setup buffers .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-01-16 19:07:52 +03:00
struct cli_api_pipe_state {
2013-02-18 12:57:22 +04:00
struct tevent_context * ev ;
2009-01-22 20:52:15 +03:00
struct rpc_cli_transport * transport ;
2009-01-16 19:07:52 +03:00
uint8_t * rdata ;
uint32_t rdata_len ;
} ;
2009-03-24 01:30:18 +03:00
static void cli_api_pipe_trans_done ( struct tevent_req * subreq ) ;
2009-03-23 23:49:19 +03:00
static void cli_api_pipe_write_done ( struct tevent_req * subreq ) ;
2009-03-24 01:03:37 +03:00
static void cli_api_pipe_read_done ( struct tevent_req * subreq ) ;
2009-01-16 19:07:52 +03:00
2009-03-24 00:13:44 +03:00
static struct tevent_req * cli_api_pipe_send ( TALLOC_CTX * mem_ctx ,
2013-02-18 12:57:22 +04:00
struct tevent_context * ev ,
2009-03-24 00:13:44 +03:00
struct rpc_cli_transport * transport ,
uint8_t * data , size_t data_len ,
uint32_t max_rdata_len )
2009-01-16 19:07:52 +03:00
{
2009-03-24 01:30:18 +03:00
struct tevent_req * req , * subreq ;
2009-01-16 19:07:52 +03:00
struct cli_api_pipe_state * state ;
NTSTATUS status ;
2009-03-24 00:13:44 +03:00
req = tevent_req_create ( mem_ctx , & state , struct cli_api_pipe_state ) ;
if ( req = = NULL ) {
2009-01-16 19:07:52 +03:00
return NULL ;
}
state - > ev = ev ;
2009-01-22 20:52:15 +03:00
state - > transport = transport ;
2009-01-16 19:07:52 +03:00
2009-01-22 20:52:15 +03:00
if ( max_rdata_len < RPC_HEADER_LEN ) {
2009-01-16 19:07:52 +03:00
/*
* For a RPC reply we always need at least RPC_HEADER_LEN
* bytes . We check this here because we will receive
* RPC_HEADER_LEN bytes in cli_trans_sock_send_done .
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto post_status ;
}
2009-01-22 20:52:15 +03:00
if ( transport - > trans_send ! = NULL ) {
subreq = transport - > trans_send ( state , ev , data , data_len ,
max_rdata_len , transport - > priv ) ;
2009-01-16 19:07:52 +03:00
if ( subreq = = NULL ) {
2009-03-24 01:30:18 +03:00
goto fail ;
2009-01-16 19:07:52 +03:00
}
2009-03-24 01:30:18 +03:00
tevent_req_set_callback ( subreq , cli_api_pipe_trans_done , req ) ;
2009-03-24 00:13:44 +03:00
return req ;
2009-01-16 19:07:52 +03:00
}
2009-01-22 20:52:15 +03:00
/*
* If the transport does not provide a " trans " routine , i . e . for
* example the ncacn_ip_tcp transport , do the write / read step here .
*/
2009-03-24 01:30:18 +03:00
subreq = rpc_write_send ( state , ev , transport , data , data_len ) ;
if ( subreq = = NULL ) {
2009-01-22 20:52:15 +03:00
goto fail ;
2009-01-16 19:07:52 +03:00
}
2009-03-24 01:30:18 +03:00
tevent_req_set_callback ( subreq , cli_api_pipe_write_done , req ) ;
2009-03-24 00:13:44 +03:00
return req ;
2009-01-16 19:07:52 +03:00
post_status :
2009-03-24 01:30:18 +03:00
tevent_req_nterror ( req , status ) ;
2009-03-24 00:13:44 +03:00
return tevent_req_post ( req , ev ) ;
2009-01-22 20:52:15 +03:00
fail :
2009-03-24 00:13:44 +03:00
TALLOC_FREE ( req ) ;
2009-01-16 19:07:52 +03:00
return NULL ;
}
2009-03-24 01:30:18 +03:00
static void cli_api_pipe_trans_done ( struct tevent_req * subreq )
2009-01-16 19:07:52 +03:00
{
2009-03-24 01:30:18 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2009-03-24 00:13:44 +03:00
struct cli_api_pipe_state * state = tevent_req_data (
req , struct cli_api_pipe_state ) ;
2009-01-16 19:07:52 +03:00
NTSTATUS status ;
2009-01-22 20:52:15 +03:00
status = state - > transport - > trans_recv ( subreq , state , & state - > rdata ,
& state - > rdata_len ) ;
2009-01-16 19:07:52 +03:00
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-03-24 00:13:44 +03:00
tevent_req_nterror ( req , status ) ;
2009-01-16 19:07:52 +03:00
return ;
}
2009-03-24 00:13:44 +03:00
tevent_req_done ( req ) ;
2009-01-16 19:07:52 +03:00
}
2009-03-23 23:49:19 +03:00
static void cli_api_pipe_write_done ( struct tevent_req * subreq )
2009-01-16 19:07:52 +03:00
{
2009-03-24 00:13:44 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_api_pipe_state * state = tevent_req_data (
req , struct cli_api_pipe_state ) ;
2009-01-16 19:07:52 +03:00
NTSTATUS status ;
2009-01-22 20:52:15 +03:00
status = rpc_write_recv ( subreq ) ;
2009-01-16 19:07:52 +03:00
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-03-24 00:13:44 +03:00
tevent_req_nterror ( req , status ) ;
2009-01-16 19:07:52 +03:00
return ;
}
2011-06-07 05:30:12 +04:00
state - > rdata = talloc_array ( state , uint8_t , RPC_HEADER_LEN ) ;
2009-03-24 00:13:44 +03:00
if ( tevent_req_nomem ( state - > rdata , req ) ) {
2009-01-16 19:07:52 +03:00
return ;
}
2009-01-22 20:52:15 +03:00
/*
* We don ' t need to use rpc_read_send here , the upper layer will cope
* with a short read , transport - > trans_send could also return less
* than state - > max_rdata_len .
*/
2009-03-24 01:03:37 +03:00
subreq = state - > transport - > read_send ( state , state - > ev , state - > rdata ,
RPC_HEADER_LEN ,
state - > transport - > priv ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
2009-01-16 19:07:52 +03:00
return ;
}
2009-03-24 01:03:37 +03:00
tevent_req_set_callback ( subreq , cli_api_pipe_read_done , req ) ;
2009-01-16 19:07:52 +03:00
}
2009-03-24 01:03:37 +03:00
static void cli_api_pipe_read_done ( struct tevent_req * subreq )
2009-01-16 19:07:52 +03:00
{
2009-03-24 01:03:37 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2009-03-24 00:13:44 +03:00
struct cli_api_pipe_state * state = tevent_req_data (
req , struct cli_api_pipe_state ) ;
2009-01-16 19:07:52 +03:00
NTSTATUS status ;
2009-01-22 20:52:15 +03:00
ssize_t received ;
2009-01-16 19:07:52 +03:00
2009-01-22 20:52:15 +03:00
status = state - > transport - > read_recv ( subreq , & received ) ;
2009-01-16 19:07:52 +03:00
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-03-24 00:13:44 +03:00
tevent_req_nterror ( req , status ) ;
2009-01-16 19:07:52 +03:00
return ;
}
2009-01-22 20:52:15 +03:00
state - > rdata_len = received ;
2009-03-24 00:13:44 +03:00
tevent_req_done ( req ) ;
2009-01-16 19:07:52 +03:00
}
2009-03-24 00:13:44 +03:00
static NTSTATUS cli_api_pipe_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
2009-01-16 19:07:52 +03:00
uint8_t * * prdata , uint32_t * prdata_len )
{
2009-03-24 00:13:44 +03:00
struct cli_api_pipe_state * state = tevent_req_data (
req , struct cli_api_pipe_state ) ;
2009-01-16 19:07:52 +03:00
NTSTATUS status ;
2009-03-24 00:13:44 +03:00
if ( tevent_req_is_nterror ( req , & status ) ) {
2009-01-16 19:07:52 +03:00
return status ;
}
* prdata = talloc_move ( mem_ctx , & state - > rdata ) ;
* prdata_len = state - > rdata_len ;
return NT_STATUS_OK ;
}
1998-03-12 00:11:04 +03:00
/****************************************************************************
2010-07-15 07:31:38 +04:00
Send data on an rpc pipe via trans . The data must be the last
2005-09-30 21:13:37 +04:00
pdu fragment of an NDR data stream .
Receive response data from an rpc pipe , which may be large . . .
1998-03-12 00:11:04 +03:00
1999-12-13 16:27:58 +03:00
Read the first fragment : unfortunately have to use SMBtrans for the first
1998-03-12 00:11:04 +03:00
bit , then SMBreadX for subsequent bits .
1999-12-13 16:27:58 +03:00
If first fragment received also wasn ' t the last fragment , continue
1998-03-12 00:11:04 +03:00
getting fragments until we _do_ receive the last fragment .
1999-12-13 16:27:58 +03:00
Request / Response PDU ' s look like the following . . .
| < - - - - - - - - - - - - - - - - - - PDU len - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - > |
| < - HDR_LEN - - > | < - - REQ LEN - - - - - - > | . . . . . . . . . . . . . | < - AUTH_HDRLEN - > | < - AUTH_LEN - - > |
+ - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - + - - - - - - - - - - - - - - - + - - - - - - - - - - - - - +
| RPC HEADER | REQ / RESP HEADER | DATA . . . . . . | AUTH_HDR | AUTH DATA |
+ - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - + - - - - - - - - - - - - - - - + - - - - - - - - - - - - - +
2005-09-30 21:13:37 +04:00
Where the presence of the AUTH_HDR and AUTH DATA are dependent on the
2003-04-16 19:39:57 +04:00
signing & sealing being negotiated .
1998-03-12 00:11:04 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-01-17 15:33:34 +03:00
struct rpc_api_pipe_state {
2013-02-18 12:57:22 +04:00
struct tevent_context * ev ;
2009-01-17 15:33:34 +03:00
struct rpc_pipe_client * cli ;
uint8_t expected_pkt_type ;
2013-10-18 01:44:35 +04:00
uint32_t call_id ;
2009-01-17 15:33:34 +03:00
2010-07-15 02:29:32 +04:00
DATA_BLOB incoming_frag ;
2010-07-13 15:59:12 +04:00
struct ncacn_packet * pkt ;
2009-01-17 15:33:34 +03:00
2010-07-15 03:39:54 +04:00
/* Incoming reply */
DATA_BLOB reply_pdu ;
size_t reply_pdu_offset ;
uint8_t endianess ;
2009-01-17 15:33:34 +03:00
} ;
2009-03-24 00:13:44 +03:00
static void rpc_api_pipe_trans_done ( struct tevent_req * subreq ) ;
2009-03-23 23:57:19 +03:00
static void rpc_api_pipe_got_pdu ( struct tevent_req * subreq ) ;
2010-09-07 22:39:20 +04:00
static void rpc_api_pipe_auth3_done ( struct tevent_req * subreq ) ;
2009-01-17 15:33:34 +03:00
2009-03-24 00:33:00 +03:00
static struct tevent_req * rpc_api_pipe_send ( TALLOC_CTX * mem_ctx ,
2013-02-18 12:57:22 +04:00
struct tevent_context * ev ,
2009-03-24 00:33:00 +03:00
struct rpc_pipe_client * cli ,
2010-07-15 07:31:38 +04:00
DATA_BLOB * data , /* Outgoing PDU */
2013-10-18 01:44:35 +04:00
uint8_t expected_pkt_type ,
uint32_t call_id )
2009-01-17 15:33:34 +03:00
{
2009-03-24 00:33:00 +03:00
struct tevent_req * req , * subreq ;
2009-01-17 15:33:34 +03:00
struct rpc_api_pipe_state * state ;
2009-01-18 14:22:14 +03:00
uint16_t max_recv_frag ;
2009-01-17 15:33:34 +03:00
NTSTATUS status ;
2009-03-24 00:33:00 +03:00
req = tevent_req_create ( mem_ctx , & state , struct rpc_api_pipe_state ) ;
if ( req = = NULL ) {
2009-01-17 15:33:34 +03:00
return NULL ;
}
state - > ev = ev ;
state - > cli = cli ;
state - > expected_pkt_type = expected_pkt_type ;
2013-10-18 01:44:35 +04:00
state - > call_id = call_id ;
2010-07-15 03:39:54 +04:00
state - > endianess = DCERPC_DREP_LE ;
2009-01-17 15:33:34 +03:00
/*
* Ensure we ' re not sending too much .
*/
2010-07-15 07:31:38 +04:00
if ( data - > length > cli - > max_xmit_frag ) {
2009-01-17 15:33:34 +03:00
status = NT_STATUS_INVALID_PARAMETER ;
goto post_status ;
}
2009-11-03 12:59:18 +03:00
DEBUG ( 5 , ( " rpc_api_pipe: %s \n " , rpccli_pipe_txt ( talloc_tos ( ) , cli ) ) ) ;
2009-01-17 15:33:34 +03:00
2010-09-07 22:39:20 +04:00
if ( state - > expected_pkt_type = = DCERPC_PKT_AUTH3 ) {
subreq = rpc_write_send ( state , ev , cli - > transport ,
data - > data , data - > length ) ;
if ( subreq = = NULL ) {
goto fail ;
}
tevent_req_set_callback ( subreq , rpc_api_pipe_auth3_done , req ) ;
return req ;
}
2010-07-15 00:15:13 +04:00
/* get the header first, then fetch the rest once we have
* the frag_length available */
max_recv_frag = RPC_HEADER_LEN ;
2009-01-18 14:22:14 +03:00
2009-01-22 20:52:15 +03:00
subreq = cli_api_pipe_send ( state , ev , cli - > transport ,
2010-07-15 07:31:38 +04:00
data - > data , data - > length , max_recv_frag ) ;
2009-01-17 15:33:34 +03:00
if ( subreq = = NULL ) {
2009-03-24 00:33:00 +03:00
goto fail ;
2009-01-17 15:33:34 +03:00
}
2009-03-24 00:33:00 +03:00
tevent_req_set_callback ( subreq , rpc_api_pipe_trans_done , req ) ;
return req ;
2009-01-17 15:33:34 +03:00
post_status :
2009-03-24 00:33:00 +03:00
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
fail :
TALLOC_FREE ( req ) ;
2009-01-17 15:33:34 +03:00
return NULL ;
}
2010-09-07 22:39:20 +04:00
static void rpc_api_pipe_auth3_done ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
NTSTATUS status ;
status = rpc_write_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return ;
}
tevent_req_done ( req ) ;
}
2009-03-24 00:13:44 +03:00
static void rpc_api_pipe_trans_done ( struct tevent_req * subreq )
2009-01-17 15:33:34 +03:00
{
2009-03-24 00:33:00 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct rpc_api_pipe_state * state = tevent_req_data (
req , struct rpc_api_pipe_state ) ;
2009-01-17 15:33:34 +03:00
NTSTATUS status ;
uint8_t * rdata = NULL ;
uint32_t rdata_len = 0 ;
status = cli_api_pipe_recv ( subreq , state , & rdata , & rdata_len ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 5 , ( " cli_api_pipe failed: %s \n " , nt_errstr ( status ) ) ) ;
2009-03-24 00:33:00 +03:00
tevent_req_nterror ( req , status ) ;
2009-01-17 15:33:34 +03:00
return ;
}
if ( rdata = = NULL ) {
DEBUG ( 3 , ( " rpc_api_pipe: %s failed to return data. \n " ,
2009-11-03 12:59:18 +03:00
rpccli_pipe_txt ( talloc_tos ( ) , state - > cli ) ) ) ;
2009-03-24 00:33:00 +03:00
tevent_req_done ( req ) ;
2009-01-17 15:33:34 +03:00
return ;
}
/*
2010-07-15 02:29:32 +04:00
* Move data on state - > incoming_frag .
2009-01-17 15:33:34 +03:00
*/
2010-07-15 02:29:32 +04:00
state - > incoming_frag . data = talloc_move ( state , & rdata ) ;
state - > incoming_frag . length = rdata_len ;
if ( ! state - > incoming_frag . data ) {
tevent_req_nterror ( req , NT_STATUS_NO_MEMORY ) ;
return ;
}
2009-01-17 15:33:34 +03:00
/* Ensure we have enough data for a pdu. */
2009-03-24 00:13:44 +03:00
subreq = get_complete_frag_send ( state , state - > ev , state - > cli ,
2010-07-12 17:36:39 +04:00
& state - > incoming_frag ) ;
2009-03-24 00:33:00 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
2009-01-17 15:33:34 +03:00
return ;
}
2009-03-24 00:13:44 +03:00
tevent_req_set_callback ( subreq , rpc_api_pipe_got_pdu , req ) ;
2009-01-17 15:33:34 +03:00
}
2009-03-23 23:57:19 +03:00
static void rpc_api_pipe_got_pdu ( struct tevent_req * subreq )
2009-01-17 15:33:34 +03:00
{
2009-03-24 00:33:00 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct rpc_api_pipe_state * state = tevent_req_data (
req , struct rpc_api_pipe_state ) ;
2009-01-17 15:33:34 +03:00
NTSTATUS status ;
2010-07-15 02:29:32 +04:00
DATA_BLOB rdata = data_blob_null ;
2009-01-17 15:33:34 +03:00
status = get_complete_frag_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 5 , ( " get_complete_frag failed: %s \n " ,
nt_errstr ( status ) ) ) ;
2009-03-24 00:33:00 +03:00
tevent_req_nterror ( req , status ) ;
2009-01-17 15:33:34 +03:00
return ;
}
2010-07-13 15:59:12 +04:00
state - > pkt = talloc ( state , struct ncacn_packet ) ;
if ( ! state - > pkt ) {
tevent_req_nterror ( req , NT_STATUS_NO_MEMORY ) ;
return ;
}
2010-08-24 01:11:32 +04:00
status = dcerpc_pull_ncacn_packet ( state - > pkt ,
2010-08-02 18:03:04 +04:00
& state - > incoming_frag ,
state - > pkt ,
! state - > endianess ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return ;
}
if ( state - > incoming_frag . length ! = state - > pkt - > frag_length ) {
DEBUG ( 5 , ( " Incorrect pdu length %u, expected %u \n " ,
( unsigned int ) state - > incoming_frag . length ,
( unsigned int ) state - > pkt - > frag_length ) ) ;
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
}
2010-07-15 03:39:54 +04:00
status = cli_pipe_validate_current_pdu ( state ,
state - > cli , state - > pkt ,
2010-07-15 02:29:32 +04:00
& state - > incoming_frag ,
state - > expected_pkt_type ,
2013-10-18 01:44:35 +04:00
state - > call_id ,
2010-07-15 02:29:32 +04:00
& rdata ,
2010-07-15 03:39:54 +04:00
& state - > reply_pdu ) ;
2009-01-17 15:33:34 +03:00
DEBUG ( 10 , ( " rpc_api_pipe: got frag len of %u at offset %u: %s \n " ,
2010-07-15 02:29:32 +04:00
( unsigned ) state - > incoming_frag . length ,
2010-07-15 03:39:54 +04:00
( unsigned ) state - > reply_pdu_offset ,
2009-01-17 15:33:34 +03:00
nt_errstr ( status ) ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-03-24 00:33:00 +03:00
tevent_req_nterror ( req , status ) ;
2009-01-17 15:33:34 +03:00
return ;
}
2010-07-13 15:59:12 +04:00
if ( ( state - > pkt - > pfc_flags & DCERPC_PFC_FLAG_FIRST )
2010-07-15 02:29:32 +04:00
& & ( state - > pkt - > drep [ 0 ] ! = DCERPC_DREP_LE ) ) {
2009-01-17 15:33:34 +03:00
/*
* Set the data type correctly for big - endian data on the
* first packet .
*/
DEBUG ( 10 , ( " rpc_api_pipe: On %s PDU data format is "
" big-endian. \n " ,
2009-11-03 12:59:18 +03:00
rpccli_pipe_txt ( talloc_tos ( ) , state - > cli ) ) ) ;
2010-07-15 03:39:54 +04:00
state - > endianess = 0x00 ; /* BIG ENDIAN */
2009-01-17 15:33:34 +03:00
}
/*
* Check endianness on subsequent packets .
*/
2010-07-15 03:39:54 +04:00
if ( state - > endianess ! = state - > pkt - > drep [ 0 ] ) {
2009-01-17 15:33:34 +03:00
DEBUG ( 0 , ( " rpc_api_pipe: Error : Endianness changed from %s to "
" %s \n " ,
2010-07-15 03:39:54 +04:00
state - > endianess ? " little " : " big " ,
state - > pkt - > drep [ 0 ] ? " little " : " big " ) ) ;
2009-03-24 00:33:00 +03:00
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
2009-01-17 15:33:34 +03:00
return ;
}
/* Now copy the data portion out of the pdu into rbuf. */
2010-07-15 03:39:54 +04:00
if ( state - > reply_pdu . length < state - > reply_pdu_offset + rdata . length ) {
if ( ! data_blob_realloc ( NULL , & state - > reply_pdu ,
state - > reply_pdu_offset + rdata . length ) ) {
tevent_req_nterror ( req , NT_STATUS_NO_MEMORY ) ;
return ;
}
2009-01-17 15:33:34 +03:00
}
2010-07-15 03:39:54 +04:00
memcpy ( state - > reply_pdu . data + state - > reply_pdu_offset ,
rdata . data , rdata . length ) ;
state - > reply_pdu_offset + = rdata . length ;
2009-01-17 15:33:34 +03:00
2010-07-15 02:29:32 +04:00
/* reset state->incoming_frag, there is no need to free it,
* it will be reallocated to the right size the next time
* it is used */
state - > incoming_frag . length = 0 ;
2009-01-17 15:33:34 +03:00
2010-07-13 15:59:12 +04:00
if ( state - > pkt - > pfc_flags & DCERPC_PFC_FLAG_LAST ) {
2010-07-15 03:39:54 +04:00
/* make sure the pdu length is right now that we
* have all the data available ( alloc hint may
* have allocated more than was actually used ) */
state - > reply_pdu . length = state - > reply_pdu_offset ;
2009-01-17 15:33:34 +03:00
DEBUG ( 10 , ( " rpc_api_pipe: %s returned %u bytes. \n " ,
2009-11-03 12:59:18 +03:00
rpccli_pipe_txt ( talloc_tos ( ) , state - > cli ) ,
2010-07-15 03:39:54 +04:00
( unsigned ) state - > reply_pdu . length ) ) ;
2009-03-24 00:33:00 +03:00
tevent_req_done ( req ) ;
2009-01-17 15:33:34 +03:00
return ;
}
subreq = get_complete_frag_send ( state , state - > ev , state - > cli ,
2010-07-12 17:36:39 +04:00
& state - > incoming_frag ) ;
2009-03-24 00:33:00 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
2009-01-17 15:33:34 +03:00
return ;
}
2009-03-23 23:57:19 +03:00
tevent_req_set_callback ( subreq , rpc_api_pipe_got_pdu , req ) ;
2009-01-17 15:33:34 +03:00
}
2009-03-24 00:33:00 +03:00
static NTSTATUS rpc_api_pipe_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
2010-07-13 16:29:21 +04:00
struct ncacn_packet * * pkt ,
2010-07-15 03:39:54 +04:00
DATA_BLOB * reply_pdu )
2009-01-17 15:33:34 +03:00
{
2009-03-24 00:33:00 +03:00
struct rpc_api_pipe_state * state = tevent_req_data (
req , struct rpc_api_pipe_state ) ;
2009-01-17 15:33:34 +03:00
NTSTATUS status ;
2009-03-24 00:33:00 +03:00
if ( tevent_req_is_nterror ( req , & status ) ) {
2009-01-17 15:33:34 +03:00
return status ;
}
2010-07-15 03:39:54 +04:00
/* return data to caller and assign it ownership of memory */
if ( reply_pdu ) {
reply_pdu - > data = talloc_move ( mem_ctx , & state - > reply_pdu . data ) ;
reply_pdu - > length = state - > reply_pdu . length ;
state - > reply_pdu . length = 0 ;
} else {
data_blob_free ( & state - > reply_pdu ) ;
}
2009-01-17 15:33:34 +03:00
2010-07-13 16:29:21 +04:00
if ( pkt ) {
* pkt = talloc_steal ( mem_ctx , state - > pkt ) ;
}
2009-01-17 15:33:34 +03:00
return NT_STATUS_OK ;
}
2005-09-30 21:13:37 +04:00
/*******************************************************************
Creates NTLMSSP auth bind .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-12-31 16:08:25 +04:00
static NTSTATUS create_generic_auth_rpc_bind_req ( struct rpc_pipe_client * cli ,
2011-07-26 11:20:35 +04:00
TALLOC_CTX * mem_ctx ,
2014-01-04 01:41:33 +04:00
DATA_BLOB * auth_token ,
bool * client_hdr_signing )
1998-03-12 00:11:04 +03:00
{
2011-10-27 16:50:37 +04:00
struct gensec_security * gensec_security ;
2007-05-14 16:16:20 +04:00
DATA_BLOB null_blob = data_blob_null ;
2014-01-04 01:41:33 +04:00
NTSTATUS status ;
2010-09-04 00:27:47 +04:00
2011-10-27 16:50:37 +04:00
gensec_security = talloc_get_type_abort ( cli - > auth - > auth_ctx ,
struct gensec_security ) ;
Makefile.in :
- added srvsvc client files
clientgen.c :
- replaced cli_error(cli, int *cls, int *err) with
cli_error(cli, uint8 cls, uint32 *err). this version detects
32 bit status messages. the DOS error "MORE_DATA", the
equivalent of the 32 bit *warning* 0x8000 0005
(STATUS_BUFFER_OVERFLOW), was being processed as an error,
terminating the cli_receive_trans() call.
cli_pipe.c :
- replaced calls that had been incorrectly modified from
32 bit warnings (0x8000 0005 - STATUS_BUFFER_OVERFLOW)
to 8 bit DOS errors (0x01 0xEA - MORE_DATA).
the use of the old version of cli_error (DOS only)
instead of the new one (DOS and 32 bit) caused the
dce/rpc client code to fail.
- replaced 2 space indentation with tab indentation in all functions.
cli_srvsvc.c :
cmd_srvsvc.c :
- added these files back in, fixing them up to use jeremy's
modified versions of the dce/rpc client functions.
parse_srv.c :
- added back in some "unused" functions required by dce/rpc
client-side code. it would be helpful if all such "unused"
functions could be added back in.
rpcclient.c :
- added "session", "file", "share", "connection" enumeration
functions back in. these are equivalent to nt's "NetXXXXXEnum"
Win32 (MSDN) functions.
- added "srvinfo" function back in. this is equivalent to
nt's NetServerGetInfo Win32 (MSDN) function.
(This used to be commit bcf39ffdcc64e049bca2d70a394a99976291e81d)
1998-10-03 01:09:23 +04:00
2012-02-06 11:14:54 +04:00
DEBUG ( 5 , ( " create_generic_auth_rpc_bind_req: generate first token \n " ) ) ;
2013-12-13 22:56:13 +04:00
status = gensec_update ( gensec_security , mem_ctx , null_blob , auth_token ) ;
2014-01-04 01:41:33 +04:00
if ( ! NT_STATUS_IS_OK ( status ) & &
! NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) )
{
return status ;
}
2014-01-21 18:18:01 +04:00
if ( client_hdr_signing = = NULL ) {
return status ;
2014-01-04 01:41:33 +04:00
}
2014-01-21 18:18:01 +04:00
if ( cli - > auth - > auth_level < DCERPC_AUTH_LEVEL_INTEGRITY ) {
* client_hdr_signing = false ;
return status ;
}
* client_hdr_signing = gensec_have_feature ( gensec_security ,
GENSEC_FEATURE_SIGN_PKT_HEADER ) ;
2014-01-04 01:41:33 +04:00
return status ;
2005-09-30 21:13:37 +04:00
}
2003-04-09 19:54:17 +04:00
2005-09-30 21:13:37 +04:00
/*******************************************************************
Creates the internals of a DCE / RPC bind request or alter context PDU .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-15 07:31:38 +04:00
static NTSTATUS create_bind_or_alt_ctx_internal ( TALLOC_CTX * mem_ctx ,
enum dcerpc_pkt_type ptype ,
2005-09-30 21:13:37 +04:00
uint32 rpc_call_id ,
2009-07-05 12:13:03 +04:00
const struct ndr_syntax_id * abstract ,
const struct ndr_syntax_id * transfer ,
2010-07-15 07:31:38 +04:00
const DATA_BLOB * auth_info ,
2014-01-04 01:41:33 +04:00
bool client_hdr_signing ,
2010-07-15 07:31:38 +04:00
DATA_BLOB * blob )
2005-09-30 21:13:37 +04:00
{
2009-03-25 01:56:42 +03:00
uint16 auth_len = auth_info - > length ;
2009-03-24 20:21:18 +03:00
NTSTATUS status ;
union dcerpc_payload u ;
2010-07-15 03:57:01 +04:00
struct dcerpc_ctx_list ctx_list ;
2014-01-04 01:41:33 +04:00
uint8_t pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST ;
2005-06-08 07:48:40 +04:00
2010-07-14 21:56:13 +04:00
if ( auth_len ) {
auth_len - = DCERPC_AUTH_TRAILER_LENGTH ;
}
2014-01-04 01:41:33 +04:00
if ( client_hdr_signing ) {
pfc_flags | = DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN ;
}
2010-07-15 03:57:01 +04:00
ctx_list . context_id = 0 ;
ctx_list . num_transfer_syntaxes = 1 ;
ctx_list . abstract_syntax = * abstract ;
2010-07-16 03:11:39 +04:00
ctx_list . transfer_syntaxes = ( struct ndr_syntax_id * ) discard_const ( transfer ) ;
2010-07-15 03:57:01 +04:00
2009-03-24 20:21:18 +03:00
u . bind . max_xmit_frag = RPC_MAX_PDU_FRAG_LEN ;
u . bind . max_recv_frag = RPC_MAX_PDU_FRAG_LEN ;
u . bind . assoc_group_id = 0x0 ;
u . bind . num_contexts = 1 ;
2010-07-15 03:57:01 +04:00
u . bind . ctx_list = & ctx_list ;
2009-03-25 01:56:42 +03:00
u . bind . auth_info = * auth_info ;
2005-09-30 21:13:37 +04:00
2010-07-15 07:31:38 +04:00
status = dcerpc_push_ncacn_packet ( mem_ctx ,
2014-01-04 01:41:33 +04:00
ptype , pfc_flags ,
2010-07-14 21:56:13 +04:00
auth_len ,
2009-03-24 20:21:18 +03:00
rpc_call_id ,
2010-07-11 20:18:13 +04:00
& u ,
2010-07-15 07:31:38 +04:00
blob ) ;
2009-03-24 20:21:18 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-07-15 07:31:38 +04:00
DEBUG ( 0 , ( " Failed to marshall bind/alter ncacn_packet. \n " ) ) ;
2009-03-24 20:21:18 +03:00
return status ;
1999-12-13 16:27:58 +03:00
}
Makefile.in :
- added srvsvc client files
clientgen.c :
- replaced cli_error(cli, int *cls, int *err) with
cli_error(cli, uint8 cls, uint32 *err). this version detects
32 bit status messages. the DOS error "MORE_DATA", the
equivalent of the 32 bit *warning* 0x8000 0005
(STATUS_BUFFER_OVERFLOW), was being processed as an error,
terminating the cli_receive_trans() call.
cli_pipe.c :
- replaced calls that had been incorrectly modified from
32 bit warnings (0x8000 0005 - STATUS_BUFFER_OVERFLOW)
to 8 bit DOS errors (0x01 0xEA - MORE_DATA).
the use of the old version of cli_error (DOS only)
instead of the new one (DOS and 32 bit) caused the
dce/rpc client code to fail.
- replaced 2 space indentation with tab indentation in all functions.
cli_srvsvc.c :
cmd_srvsvc.c :
- added these files back in, fixing them up to use jeremy's
modified versions of the dce/rpc client functions.
parse_srv.c :
- added back in some "unused" functions required by dce/rpc
client-side code. it would be helpful if all such "unused"
functions could be added back in.
rpcclient.c :
- added "session", "file", "share", "connection" enumeration
functions back in. these are equivalent to nt's "NetXXXXXEnum"
Win32 (MSDN) functions.
- added "srvinfo" function back in. this is equivalent to
nt's NetServerGetInfo Win32 (MSDN) function.
(This used to be commit bcf39ffdcc64e049bca2d70a394a99976291e81d)
1998-10-03 01:09:23 +04:00
Jeremy requested that I get my NTLMSSP patch into CVS. He didn't request
the schannel code, but I've included that anyway. :-)
This patch revives the client-side NTLMSSP support for RPC named pipes
in Samba, and cleans up the client and server schannel code. The use of the
new code is enabled by the 'sign', 'seal' and 'schannel' commands in
rpcclient.
The aim was to prove that our separate NTLMSSP client library actually
implements NTLMSSP signing and sealing as per Microsoft's NTLMv1 implementation,
in the hope that knowing this will assist us in correctly implementing
NTLMSSP signing for SMB packets. (Still not yet functional)
This patch replaces the NTLMSSP implementation in rpc_client/cli_pipe.c with
calls to libsmb/ntlmssp.c. In the process, we have gained the ability to
use the more secure NT password, and the ability to sign-only, instead of
having to seal the pipe connection. (Previously we were limited to sealing,
and could only use the LM-password derived key).
Our new client-side NTLMSSP code also needed alteration to cope with our
comparatively simple server-side implementation. A future step is to replace
it with calls to the same NTLMSSP library.
Also included in this patch is the schannel 'sign only' patch I submitted to
the team earlier. While not enabled (and not functional, at this stage) the
work in this patch makes the code paths *much* easier to follow. I have also
included similar hooks in rpccleint to allow the use of schannel on *any* pipe.
rpcclient now defaults to not using schannel (or any other extra per-pipe
authenticiation) for any connection. The 'schannel' command enables schannel
for all pipes until disabled.
This code is also much more secure than the previous code, as changes to our
cli_pipe routines ensure that the authentication footer cannot be removed
by an attacker, and more error states are correctly handled.
(The same needs to be done to our server)
Andrew Bartlett
(This used to be commit 5472ddc9eaf4e79c5b2e1c8ee8c7f190dc285f19)
2003-07-14 12:46:32 +04:00
return NT_STATUS_OK ;
1998-03-12 00:11:04 +03:00
}
1998-10-09 03:57:46 +04:00
/*******************************************************************
2005-09-30 21:13:37 +04:00
Creates a DCE / RPC bind request .
1998-10-09 03:57:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2010-07-15 07:31:38 +04:00
static NTSTATUS create_rpc_bind_req ( TALLOC_CTX * mem_ctx ,
struct rpc_pipe_client * cli ,
2010-07-20 19:49:23 +04:00
struct pipe_auth_data * auth ,
2009-03-25 01:56:42 +03:00
uint32 rpc_call_id ,
const struct ndr_syntax_id * abstract ,
const struct ndr_syntax_id * transfer ,
2010-07-15 07:31:38 +04:00
DATA_BLOB * rpc_out )
1998-10-09 03:57:46 +04:00
{
2010-07-30 04:20:49 +04:00
DATA_BLOB auth_token = data_blob_null ;
2009-03-25 01:56:42 +03:00
DATA_BLOB auth_info = data_blob_null ;
2005-09-30 21:13:37 +04:00
NTSTATUS ret = NT_STATUS_OK ;
1999-12-13 16:27:58 +03:00
2010-07-20 19:49:23 +04:00
switch ( auth - > auth_type ) {
2010-07-20 21:26:36 +04:00
case DCERPC_AUTH_TYPE_SCHANNEL :
case DCERPC_AUTH_TYPE_NTLMSSP :
2012-01-02 06:06:29 +04:00
case DCERPC_AUTH_TYPE_KRB5 :
2012-02-06 05:40:38 +04:00
case DCERPC_AUTH_TYPE_SPNEGO :
2014-01-04 01:41:33 +04:00
ret = create_generic_auth_rpc_bind_req ( cli , mem_ctx ,
& auth_token ,
& auth - > client_hdr_signing ) ;
2012-02-06 06:37:12 +04:00
if ( ! NT_STATUS_IS_OK ( ret ) & &
! NT_STATUS_EQUAL ( ret , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
2010-07-20 19:49:23 +04:00
return ret ;
}
break ;
1998-10-09 03:57:46 +04:00
2011-03-01 13:49:20 +03:00
case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM :
auth_token = data_blob_talloc ( mem_ctx ,
" NCALRPC_AUTH_TOKEN " ,
18 ) ;
break ;
2010-07-20 21:26:36 +04:00
case DCERPC_AUTH_TYPE_NONE :
2010-07-20 19:49:23 +04:00
break ;
2005-09-30 21:13:37 +04:00
2010-07-20 19:49:23 +04:00
default :
/* "Can't" happen. */
return NT_STATUS_INVALID_INFO_CLASS ;
1999-12-13 16:27:58 +03:00
}
1998-10-09 03:57:46 +04:00
2010-07-30 04:20:49 +04:00
if ( auth_token . length ! = 0 ) {
ret = dcerpc_push_dcerpc_auth ( cli ,
auth - > auth_type ,
auth - > auth_level ,
0 , /* auth_pad_length */
1 , /* auth_context_id */
& auth_token ,
& auth_info ) ;
if ( ! NT_STATUS_IS_OK ( ret ) ) {
return ret ;
}
data_blob_free ( & auth_token ) ;
}
2010-07-15 07:31:38 +04:00
ret = create_bind_or_alt_ctx_internal ( mem_ctx ,
DCERPC_PKT_BIND ,
2009-03-25 01:56:42 +03:00
rpc_call_id ,
abstract ,
transfer ,
2010-07-15 07:31:38 +04:00
& auth_info ,
2014-01-04 01:41:33 +04:00
auth - > client_hdr_signing ,
2010-07-15 07:31:38 +04:00
rpc_out ) ;
2005-09-30 21:13:37 +04:00
return ret ;
}
1998-10-09 03:57:46 +04:00
2005-09-30 21:13:37 +04:00
/*******************************************************************
External interface .
Does an rpc request on a pipe . Incoming data is NDR encoded in in_data .
Reply is NDR encoded in out_data . Splits the data stream into RPC PDU ' s
and deals with signing / sealing details .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2009-01-17 19:52:35 +03:00
struct rpc_api_pipe_req_state {
2013-02-18 12:57:22 +04:00
struct tevent_context * ev ;
2009-01-17 19:52:35 +03:00
struct rpc_pipe_client * cli ;
uint8_t op_num ;
uint32_t call_id ;
2014-01-05 10:56:20 +04:00
const DATA_BLOB * req_data ;
2009-01-17 19:52:35 +03:00
uint32_t req_data_sent ;
2014-01-05 11:12:45 +04:00
DATA_BLOB req_trailer ;
uint32_t req_trailer_sent ;
bool verify_bitmask1 ;
bool verify_pcontext ;
2010-07-15 07:31:38 +04:00
DATA_BLOB rpc_out ;
2010-07-15 03:39:54 +04:00
DATA_BLOB reply_pdu ;
2009-01-17 19:52:35 +03:00
} ;
2009-03-23 23:49:19 +03:00
static void rpc_api_pipe_req_write_done ( struct tevent_req * subreq ) ;
2009-03-24 00:33:00 +03:00
static void rpc_api_pipe_req_done ( struct tevent_req * subreq ) ;
2014-01-05 11:12:45 +04:00
static NTSTATUS prepare_verification_trailer ( struct rpc_api_pipe_req_state * state ) ;
2009-01-17 19:52:35 +03:00
static NTSTATUS prepare_next_frag ( struct rpc_api_pipe_req_state * state ,
bool * is_last_frag ) ;
2014-01-05 09:31:44 +04:00
static struct tevent_req * rpc_api_pipe_req_send ( TALLOC_CTX * mem_ctx ,
2013-02-18 12:57:22 +04:00
struct tevent_context * ev ,
2009-03-24 00:49:29 +03:00
struct rpc_pipe_client * cli ,
uint8_t op_num ,
2014-01-05 10:56:20 +04:00
const DATA_BLOB * req_data )
2009-01-17 19:52:35 +03:00
{
2009-03-24 00:49:29 +03:00
struct tevent_req * req , * subreq ;
2009-01-17 19:52:35 +03:00
struct rpc_api_pipe_req_state * state ;
NTSTATUS status ;
bool is_last_frag ;
2009-03-24 00:49:29 +03:00
req = tevent_req_create ( mem_ctx , & state ,
struct rpc_api_pipe_req_state ) ;
if ( req = = NULL ) {
2009-01-17 19:52:35 +03:00
return NULL ;
}
state - > ev = ev ;
state - > cli = cli ;
state - > op_num = op_num ;
state - > req_data = req_data ;
state - > req_data_sent = 0 ;
state - > call_id = get_rpc_call_id ( ) ;
2010-07-15 03:39:54 +04:00
state - > reply_pdu = data_blob_null ;
2010-07-15 07:31:38 +04:00
state - > rpc_out = data_blob_null ;
2009-01-17 19:52:35 +03:00
2010-07-14 21:56:13 +04:00
if ( cli - > max_xmit_frag < DCERPC_REQUEST_LENGTH
+ RPC_MAX_SIGN_SIZE ) {
2009-01-17 19:52:35 +03:00
/* Server is screwed up ! */
status = NT_STATUS_INVALID_PARAMETER ;
goto post_status ;
}
2014-01-05 11:12:45 +04:00
status = prepare_verification_trailer ( state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto post_status ;
}
2009-01-17 19:52:35 +03:00
status = prepare_next_frag ( state , & is_last_frag ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto post_status ;
}
if ( is_last_frag ) {
subreq = rpc_api_pipe_send ( state , ev , state - > cli ,
2010-07-15 07:31:38 +04:00
& state - > rpc_out ,
2013-10-18 01:44:35 +04:00
DCERPC_PKT_RESPONSE ,
state - > call_id ) ;
2009-01-17 19:52:35 +03:00
if ( subreq = = NULL ) {
2009-03-24 00:33:00 +03:00
goto fail ;
2009-01-17 19:52:35 +03:00
}
2009-03-24 00:49:29 +03:00
tevent_req_set_callback ( subreq , rpc_api_pipe_req_done , req ) ;
2009-01-17 19:52:35 +03:00
} else {
2010-07-15 07:31:38 +04:00
subreq = rpc_write_send ( state , ev , cli - > transport ,
state - > rpc_out . data ,
state - > rpc_out . length ) ;
2009-03-24 00:33:00 +03:00
if ( subreq = = NULL ) {
goto fail ;
2009-01-17 19:52:35 +03:00
}
2009-03-24 00:33:00 +03:00
tevent_req_set_callback ( subreq , rpc_api_pipe_req_write_done ,
2009-03-24 00:49:29 +03:00
req ) ;
2009-01-17 19:52:35 +03:00
}
2009-03-24 00:49:29 +03:00
return req ;
2009-01-17 19:52:35 +03:00
post_status :
2009-03-24 00:49:29 +03:00
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
2009-03-24 00:33:00 +03:00
fail :
2009-03-24 00:49:29 +03:00
TALLOC_FREE ( req ) ;
2009-01-17 19:52:35 +03:00
return NULL ;
}
2014-01-05 11:12:45 +04:00
static NTSTATUS prepare_verification_trailer ( struct rpc_api_pipe_req_state * state )
{
struct pipe_auth_data * a = state - > cli - > auth ;
struct dcerpc_sec_verification_trailer * t ;
struct dcerpc_sec_vt * c = NULL ;
struct ndr_push * ndr = NULL ;
enum ndr_err_code ndr_err ;
size_t align = 0 ;
size_t pad = 0 ;
if ( a = = NULL ) {
return NT_STATUS_OK ;
}
if ( a - > auth_level < DCERPC_AUTH_LEVEL_INTEGRITY ) {
return NT_STATUS_OK ;
}
t = talloc_zero ( state , struct dcerpc_sec_verification_trailer ) ;
if ( t = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
if ( ! a - > verified_bitmask1 ) {
t - > commands = talloc_realloc ( t , t - > commands ,
struct dcerpc_sec_vt ,
t - > count . count + 1 ) ;
if ( t - > commands = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
c = & t - > commands [ t - > count . count + + ] ;
ZERO_STRUCTP ( c ) ;
c - > command = DCERPC_SEC_VT_COMMAND_BITMASK1 ;
if ( a - > client_hdr_signing ) {
c - > u . bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING ;
}
state - > verify_bitmask1 = true ;
}
if ( ! state - > cli - > verified_pcontext ) {
t - > commands = talloc_realloc ( t , t - > commands ,
struct dcerpc_sec_vt ,
t - > count . count + 1 ) ;
if ( t - > commands = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
c = & t - > commands [ t - > count . count + + ] ;
ZERO_STRUCTP ( c ) ;
c - > command = DCERPC_SEC_VT_COMMAND_PCONTEXT ;
c - > u . pcontext . abstract_syntax = state - > cli - > abstract_syntax ;
c - > u . pcontext . transfer_syntax = state - > cli - > transfer_syntax ;
state - > verify_pcontext = true ;
}
if ( ! a - > hdr_signing ) {
t - > commands = talloc_realloc ( t , t - > commands ,
struct dcerpc_sec_vt ,
t - > count . count + 1 ) ;
if ( t - > commands = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
c = & t - > commands [ t - > count . count + + ] ;
ZERO_STRUCTP ( c ) ;
c - > command = DCERPC_SEC_VT_COMMAND_HEADER2 ;
c - > u . header2 . ptype = DCERPC_PKT_REQUEST ;
c - > u . header2 . drep [ 0 ] = DCERPC_DREP_LE ;
c - > u . header2 . drep [ 1 ] = 0 ;
c - > u . header2 . drep [ 2 ] = 0 ;
c - > u . header2 . drep [ 3 ] = 0 ;
c - > u . header2 . call_id = state - > call_id ;
c - > u . header2 . context_id = 0 ;
c - > u . header2 . opnum = state - > op_num ;
}
if ( t - > count . count = = 0 ) {
TALLOC_FREE ( t ) ;
return NT_STATUS_OK ;
}
c = & t - > commands [ t - > count . count - 1 ] ;
c - > command | = DCERPC_SEC_VT_COMMAND_END ;
if ( DEBUGLEVEL > = 10 ) {
NDR_PRINT_DEBUG ( dcerpc_sec_verification_trailer , t ) ;
}
ndr = ndr_push_init_ctx ( state ) ;
if ( ndr = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
ndr_err = ndr_push_dcerpc_sec_verification_trailer ( ndr ,
NDR_SCALARS | NDR_BUFFERS ,
t ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return ndr_map_error2ntstatus ( ndr_err ) ;
}
state - > req_trailer = ndr_push_blob ( ndr ) ;
align = state - > req_data - > length & 0x3 ;
if ( align > 0 ) {
pad = 4 - align ;
}
if ( pad > 0 ) {
bool ok ;
uint8_t * p ;
const uint8_t zeros [ 4 ] = { 0 , } ;
ok = data_blob_append ( ndr , & state - > req_trailer , zeros , pad ) ;
if ( ! ok ) {
return NT_STATUS_NO_MEMORY ;
}
/* move the padding to the start */
p = state - > req_trailer . data ;
memmove ( p + pad , p , state - > req_trailer . length - pad ) ;
memset ( p , 0 , pad ) ;
}
return NT_STATUS_OK ;
}
2009-01-17 19:52:35 +03:00
static NTSTATUS prepare_next_frag ( struct rpc_api_pipe_req_state * state ,
bool * is_last_frag )
{
2010-07-30 19:27:40 +04:00
size_t auth_len ;
size_t frag_len ;
2009-01-17 19:52:35 +03:00
uint8_t flags = 0 ;
2010-07-30 19:27:40 +04:00
size_t pad_len ;
size_t data_left ;
2014-01-05 11:12:45 +04:00
size_t data_thistime ;
size_t trailer_left ;
size_t trailer_thistime = 0 ;
size_t total_left ;
size_t total_thistime ;
2009-01-17 19:52:35 +03:00
NTSTATUS status ;
2014-01-05 11:12:45 +04:00
bool ok ;
2009-04-02 02:35:19 +04:00
union dcerpc_payload u ;
2009-01-17 19:52:35 +03:00
2010-07-15 16:48:51 +04:00
data_left = state - > req_data - > length - state - > req_data_sent ;
2014-01-05 11:12:45 +04:00
trailer_left = state - > req_trailer . length - state - > req_trailer_sent ;
total_left = data_left + trailer_left ;
if ( ( total_left < data_left ) | | ( total_left < trailer_left ) ) {
/*
* overflow
*/
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
2009-01-17 19:52:35 +03:00
2010-07-30 21:12:35 +04:00
status = dcerpc_guess_sizes ( state - > cli - > auth ,
2014-01-05 11:12:45 +04:00
DCERPC_REQUEST_LENGTH , total_left ,
2010-07-30 19:27:40 +04:00
state - > cli - > max_xmit_frag ,
2010-07-30 21:12:35 +04:00
CLIENT_NDR_PADDING_SIZE ,
2014-01-05 11:12:45 +04:00
& total_thistime ,
2010-07-30 19:27:40 +04:00
& frag_len , & auth_len , & pad_len ) ;
2010-07-23 00:14:16 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2009-01-17 19:52:35 +03:00
if ( state - > req_data_sent = = 0 ) {
2009-09-16 10:54:31 +04:00
flags = DCERPC_PFC_FLAG_FIRST ;
2009-01-17 19:52:35 +03:00
}
2014-01-05 11:12:45 +04:00
if ( total_thistime = = total_left ) {
2009-09-16 10:54:31 +04:00
flags | = DCERPC_PFC_FLAG_LAST ;
2009-01-17 19:52:35 +03:00
}
2014-01-05 11:12:45 +04:00
data_thistime = MIN ( total_thistime , data_left ) ;
if ( data_thistime < total_thistime ) {
trailer_thistime = total_thistime - data_thistime ;
}
2010-07-15 07:31:38 +04:00
data_blob_free ( & state - > rpc_out ) ;
2009-01-17 19:52:35 +03:00
2009-04-02 02:35:19 +04:00
ZERO_STRUCT ( u . request ) ;
2009-01-17 19:52:35 +03:00
2014-01-05 11:12:45 +04:00
u . request . alloc_hint = total_left ;
2009-04-02 02:35:19 +04:00
u . request . context_id = 0 ;
u . request . opnum = state - > op_num ;
2009-01-17 19:52:35 +03:00
2010-07-15 07:31:38 +04:00
status = dcerpc_push_ncacn_packet ( state ,
2009-04-02 02:35:19 +04:00
DCERPC_PKT_REQUEST ,
flags ,
auth_len ,
state - > call_id ,
2010-07-11 20:18:13 +04:00
& u ,
2010-07-15 07:31:38 +04:00
& state - > rpc_out ) ;
2009-04-02 02:35:19 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2009-01-17 19:52:35 +03:00
2010-07-09 03:17:13 +04:00
/* explicitly set frag_len here as dcerpc_push_ncacn_packet() can't
2010-07-19 17:07:22 +04:00
* compute it right for requests because the auth trailer is missing
* at this stage */
2010-07-15 07:31:38 +04:00
dcerpc_set_frag_length ( & state - > rpc_out , frag_len ) ;
2009-01-17 19:52:35 +03:00
2014-01-05 11:12:45 +04:00
if ( data_thistime > 0 ) {
/* Copy in the data. */
ok = data_blob_append ( NULL , & state - > rpc_out ,
2010-07-15 16:48:51 +04:00
state - > req_data - > data + state - > req_data_sent ,
2014-01-05 11:12:45 +04:00
data_thistime ) ;
if ( ! ok ) {
return NT_STATUS_NO_MEMORY ;
}
state - > req_data_sent + = data_thistime ;
}
if ( trailer_thistime > 0 ) {
/* Copy in the verification trailer. */
ok = data_blob_append ( NULL , & state - > rpc_out ,
state - > req_trailer . data + state - > req_trailer_sent ,
trailer_thistime ) ;
if ( ! ok ) {
return NT_STATUS_NO_MEMORY ;
}
state - > req_trailer_sent + = trailer_thistime ;
2009-01-17 19:52:35 +03:00
}
2010-07-21 21:33:09 +04:00
switch ( state - > cli - > auth - > auth_level ) {
case DCERPC_AUTH_LEVEL_NONE :
case DCERPC_AUTH_LEVEL_CONNECT :
case DCERPC_AUTH_LEVEL_PACKET :
break ;
case DCERPC_AUTH_LEVEL_INTEGRITY :
case DCERPC_AUTH_LEVEL_PRIVACY :
2010-07-23 00:14:16 +04:00
status = dcerpc_add_auth_footer ( state - > cli - > auth , pad_len ,
2010-07-21 21:33:09 +04:00
& state - > rpc_out ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
break ;
default :
return NT_STATUS_INVALID_PARAMETER ;
2009-01-17 19:52:35 +03:00
}
2009-09-16 10:54:31 +04:00
* is_last_frag = ( ( flags & DCERPC_PFC_FLAG_LAST ) ! = 0 ) ;
2009-01-17 19:52:35 +03:00
return status ;
}
2009-03-23 23:49:19 +03:00
static void rpc_api_pipe_req_write_done ( struct tevent_req * subreq )
2009-01-17 19:52:35 +03:00
{
2009-03-24 00:49:29 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct rpc_api_pipe_req_state * state = tevent_req_data (
req , struct rpc_api_pipe_req_state ) ;
2009-01-17 19:52:35 +03:00
NTSTATUS status ;
bool is_last_frag ;
status = rpc_write_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-03-24 00:49:29 +03:00
tevent_req_nterror ( req , status ) ;
2009-01-17 19:52:35 +03:00
return ;
}
status = prepare_next_frag ( state , & is_last_frag ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-03-24 00:49:29 +03:00
tevent_req_nterror ( req , status ) ;
2009-01-17 19:52:35 +03:00
return ;
}
if ( is_last_frag ) {
2009-03-24 00:33:00 +03:00
subreq = rpc_api_pipe_send ( state , state - > ev , state - > cli ,
2010-07-15 07:31:38 +04:00
& state - > rpc_out ,
2013-10-18 01:44:35 +04:00
DCERPC_PKT_RESPONSE ,
state - > call_id ) ;
2009-03-24 00:49:29 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
2009-01-17 19:52:35 +03:00
return ;
}
2009-03-24 00:33:00 +03:00
tevent_req_set_callback ( subreq , rpc_api_pipe_req_done , req ) ;
2009-01-17 19:52:35 +03:00
} else {
2010-07-15 07:31:38 +04:00
subreq = rpc_write_send ( state , state - > ev ,
state - > cli - > transport ,
state - > rpc_out . data ,
state - > rpc_out . length ) ;
2009-03-24 00:49:29 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
2009-01-17 19:52:35 +03:00
return ;
}
2009-03-23 23:49:19 +03:00
tevent_req_set_callback ( subreq , rpc_api_pipe_req_write_done ,
req ) ;
2009-01-17 19:52:35 +03:00
}
}
2009-03-24 00:33:00 +03:00
static void rpc_api_pipe_req_done ( struct tevent_req * subreq )
2009-01-17 19:52:35 +03:00
{
2009-03-24 00:49:29 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct rpc_api_pipe_req_state * state = tevent_req_data (
req , struct rpc_api_pipe_req_state ) ;
2009-01-17 19:52:35 +03:00
NTSTATUS status ;
2010-07-13 16:29:21 +04:00
status = rpc_api_pipe_recv ( subreq , state , NULL , & state - > reply_pdu ) ;
2009-01-17 19:52:35 +03:00
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-03-24 00:49:29 +03:00
tevent_req_nterror ( req , status ) ;
2009-01-17 19:52:35 +03:00
return ;
}
2014-01-05 11:12:45 +04:00
if ( state - > cli - > auth = = NULL ) {
tevent_req_done ( req ) ;
return ;
}
if ( state - > verify_bitmask1 ) {
state - > cli - > auth - > verified_bitmask1 = true ;
}
if ( state - > verify_pcontext ) {
state - > cli - > verified_pcontext = true ;
}
2009-03-24 00:49:29 +03:00
tevent_req_done ( req ) ;
2009-01-17 19:52:35 +03:00
}
2014-01-05 09:31:44 +04:00
static NTSTATUS rpc_api_pipe_req_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
2010-07-15 03:39:54 +04:00
DATA_BLOB * reply_pdu )
2009-01-17 19:52:35 +03:00
{
2009-03-24 00:49:29 +03:00
struct rpc_api_pipe_req_state * state = tevent_req_data (
req , struct rpc_api_pipe_req_state ) ;
2009-01-17 19:52:35 +03:00
NTSTATUS status ;
2009-03-24 00:49:29 +03:00
if ( tevent_req_is_nterror ( req , & status ) ) {
2009-01-22 19:53:22 +03:00
/*
* We always have to initialize to reply pdu , even if there is
* none . The rpccli_ * caller routines expect this .
*/
2010-07-15 03:39:54 +04:00
* reply_pdu = data_blob_null ;
2009-01-17 19:52:35 +03:00
return status ;
}
2010-07-15 03:39:54 +04:00
/* return data to caller and assign it ownership of memory */
reply_pdu - > data = talloc_move ( mem_ctx , & state - > reply_pdu . data ) ;
reply_pdu - > length = state - > reply_pdu . length ;
state - > reply_pdu . length = 0 ;
2009-01-17 19:52:35 +03:00
return NT_STATUS_OK ;
}
1998-03-12 00:11:04 +03:00
/****************************************************************************
2005-09-30 21:13:37 +04:00
Check the rpc bind acknowledge response .
1998-03-12 00:11:04 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-04-24 02:45:53 +04:00
2009-04-02 03:05:55 +04:00
static bool check_bind_response ( const struct dcerpc_bind_ack * r ,
2009-07-05 12:13:03 +04:00
const struct ndr_syntax_id * transfer )
1998-03-12 00:11:04 +03:00
{
2009-04-02 03:05:55 +04:00
struct dcerpc_ack_ctx ctx ;
if ( r - > secondary_address_size = = 0 ) {
2004-07-07 22:14:16 +04:00
DEBUG ( 4 , ( " Ignoring length check -- ASU bug (server didn't fill in the pipe name correctly) " ) ) ;
}
2009-04-02 03:05:55 +04:00
if ( r - > num_results < 1 | | ! r - > ctx_list ) {
return false ;
}
ctx = r - > ctx_list [ 0 ] ;
Makefile.in :
- added srvsvc client files
clientgen.c :
- replaced cli_error(cli, int *cls, int *err) with
cli_error(cli, uint8 cls, uint32 *err). this version detects
32 bit status messages. the DOS error "MORE_DATA", the
equivalent of the 32 bit *warning* 0x8000 0005
(STATUS_BUFFER_OVERFLOW), was being processed as an error,
terminating the cli_receive_trans() call.
cli_pipe.c :
- replaced calls that had been incorrectly modified from
32 bit warnings (0x8000 0005 - STATUS_BUFFER_OVERFLOW)
to 8 bit DOS errors (0x01 0xEA - MORE_DATA).
the use of the old version of cli_error (DOS only)
instead of the new one (DOS and 32 bit) caused the
dce/rpc client code to fail.
- replaced 2 space indentation with tab indentation in all functions.
cli_srvsvc.c :
cmd_srvsvc.c :
- added these files back in, fixing them up to use jeremy's
modified versions of the dce/rpc client functions.
parse_srv.c :
- added back in some "unused" functions required by dce/rpc
client-side code. it would be helpful if all such "unused"
functions could be added back in.
rpcclient.c :
- added "session", "file", "share", "connection" enumeration
functions back in. these are equivalent to nt's "NetXXXXXEnum"
Win32 (MSDN) functions.
- added "srvinfo" function back in. this is equivalent to
nt's NetServerGetInfo Win32 (MSDN) function.
(This used to be commit bcf39ffdcc64e049bca2d70a394a99976291e81d)
1998-10-03 01:09:23 +04:00
/* check the transfer syntax */
2009-04-02 03:05:55 +04:00
if ( ( ctx . syntax . if_version ! = transfer - > if_version ) | |
( memcmp ( & ctx . syntax . uuid , & transfer - > uuid , sizeof ( transfer - > uuid ) ) ! = 0 ) ) {
2002-11-01 03:37:45 +03:00
DEBUG ( 2 , ( " bind_rpc_pipe: transfer syntax differs \n " ) ) ;
Makefile.in :
- added srvsvc client files
clientgen.c :
- replaced cli_error(cli, int *cls, int *err) with
cli_error(cli, uint8 cls, uint32 *err). this version detects
32 bit status messages. the DOS error "MORE_DATA", the
equivalent of the 32 bit *warning* 0x8000 0005
(STATUS_BUFFER_OVERFLOW), was being processed as an error,
terminating the cli_receive_trans() call.
cli_pipe.c :
- replaced calls that had been incorrectly modified from
32 bit warnings (0x8000 0005 - STATUS_BUFFER_OVERFLOW)
to 8 bit DOS errors (0x01 0xEA - MORE_DATA).
the use of the old version of cli_error (DOS only)
instead of the new one (DOS and 32 bit) caused the
dce/rpc client code to fail.
- replaced 2 space indentation with tab indentation in all functions.
cli_srvsvc.c :
cmd_srvsvc.c :
- added these files back in, fixing them up to use jeremy's
modified versions of the dce/rpc client functions.
parse_srv.c :
- added back in some "unused" functions required by dce/rpc
client-side code. it would be helpful if all such "unused"
functions could be added back in.
rpcclient.c :
- added "session", "file", "share", "connection" enumeration
functions back in. these are equivalent to nt's "NetXXXXXEnum"
Win32 (MSDN) functions.
- added "srvinfo" function back in. this is equivalent to
nt's NetServerGetInfo Win32 (MSDN) function.
(This used to be commit bcf39ffdcc64e049bca2d70a394a99976291e81d)
1998-10-03 01:09:23 +04:00
return False ;
}
2009-04-02 03:05:55 +04:00
if ( r - > num_results ! = 0x1 | | ctx . result ! = 0 ) {
Makefile.in :
- added srvsvc client files
clientgen.c :
- replaced cli_error(cli, int *cls, int *err) with
cli_error(cli, uint8 cls, uint32 *err). this version detects
32 bit status messages. the DOS error "MORE_DATA", the
equivalent of the 32 bit *warning* 0x8000 0005
(STATUS_BUFFER_OVERFLOW), was being processed as an error,
terminating the cli_receive_trans() call.
cli_pipe.c :
- replaced calls that had been incorrectly modified from
32 bit warnings (0x8000 0005 - STATUS_BUFFER_OVERFLOW)
to 8 bit DOS errors (0x01 0xEA - MORE_DATA).
the use of the old version of cli_error (DOS only)
instead of the new one (DOS and 32 bit) caused the
dce/rpc client code to fail.
- replaced 2 space indentation with tab indentation in all functions.
cli_srvsvc.c :
cmd_srvsvc.c :
- added these files back in, fixing them up to use jeremy's
modified versions of the dce/rpc client functions.
parse_srv.c :
- added back in some "unused" functions required by dce/rpc
client-side code. it would be helpful if all such "unused"
functions could be added back in.
rpcclient.c :
- added "session", "file", "share", "connection" enumeration
functions back in. these are equivalent to nt's "NetXXXXXEnum"
Win32 (MSDN) functions.
- added "srvinfo" function back in. this is equivalent to
nt's NetServerGetInfo Win32 (MSDN) function.
(This used to be commit bcf39ffdcc64e049bca2d70a394a99976291e81d)
1998-10-03 01:09:23 +04:00
DEBUG ( 2 , ( " bind_rpc_pipe: bind denied results: %d reason: %x \n " ,
2014-01-09 19:00:23 +04:00
r - > num_results , ctx . reason . value ) ) ;
Makefile.in :
- added srvsvc client files
clientgen.c :
- replaced cli_error(cli, int *cls, int *err) with
cli_error(cli, uint8 cls, uint32 *err). this version detects
32 bit status messages. the DOS error "MORE_DATA", the
equivalent of the 32 bit *warning* 0x8000 0005
(STATUS_BUFFER_OVERFLOW), was being processed as an error,
terminating the cli_receive_trans() call.
cli_pipe.c :
- replaced calls that had been incorrectly modified from
32 bit warnings (0x8000 0005 - STATUS_BUFFER_OVERFLOW)
to 8 bit DOS errors (0x01 0xEA - MORE_DATA).
the use of the old version of cli_error (DOS only)
instead of the new one (DOS and 32 bit) caused the
dce/rpc client code to fail.
- replaced 2 space indentation with tab indentation in all functions.
cli_srvsvc.c :
cmd_srvsvc.c :
- added these files back in, fixing them up to use jeremy's
modified versions of the dce/rpc client functions.
parse_srv.c :
- added back in some "unused" functions required by dce/rpc
client-side code. it would be helpful if all such "unused"
functions could be added back in.
rpcclient.c :
- added "session", "file", "share", "connection" enumeration
functions back in. these are equivalent to nt's "NetXXXXXEnum"
Win32 (MSDN) functions.
- added "srvinfo" function back in. this is equivalent to
nt's NetServerGetInfo Win32 (MSDN) function.
(This used to be commit bcf39ffdcc64e049bca2d70a394a99976291e81d)
1998-10-03 01:09:23 +04:00
}
2005-09-30 21:13:37 +04:00
DEBUG ( 5 , ( " check_bind_response: accepted! \n " ) ) ;
Makefile.in :
- added srvsvc client files
clientgen.c :
- replaced cli_error(cli, int *cls, int *err) with
cli_error(cli, uint8 cls, uint32 *err). this version detects
32 bit status messages. the DOS error "MORE_DATA", the
equivalent of the 32 bit *warning* 0x8000 0005
(STATUS_BUFFER_OVERFLOW), was being processed as an error,
terminating the cli_receive_trans() call.
cli_pipe.c :
- replaced calls that had been incorrectly modified from
32 bit warnings (0x8000 0005 - STATUS_BUFFER_OVERFLOW)
to 8 bit DOS errors (0x01 0xEA - MORE_DATA).
the use of the old version of cli_error (DOS only)
instead of the new one (DOS and 32 bit) caused the
dce/rpc client code to fail.
- replaced 2 space indentation with tab indentation in all functions.
cli_srvsvc.c :
cmd_srvsvc.c :
- added these files back in, fixing them up to use jeremy's
modified versions of the dce/rpc client functions.
parse_srv.c :
- added back in some "unused" functions required by dce/rpc
client-side code. it would be helpful if all such "unused"
functions could be added back in.
rpcclient.c :
- added "session", "file", "share", "connection" enumeration
functions back in. these are equivalent to nt's "NetXXXXXEnum"
Win32 (MSDN) functions.
- added "srvinfo" function back in. this is equivalent to
nt's NetServerGetInfo Win32 (MSDN) function.
(This used to be commit bcf39ffdcc64e049bca2d70a394a99976291e81d)
1998-10-03 01:09:23 +04:00
return True ;
1998-03-12 00:11:04 +03:00
}
2005-09-30 21:13:37 +04:00
/*******************************************************************
Creates a DCE / RPC bind authentication response .
This is the packet that is sent back to the server once we
have received a BIND - ACK , to finish the third leg of
the authentication handshake .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-04-24 02:45:53 +04:00
2010-07-15 07:31:38 +04:00
static NTSTATUS create_rpc_bind_auth3 ( TALLOC_CTX * mem_ctx ,
struct rpc_pipe_client * cli ,
2005-09-30 21:13:37 +04:00
uint32 rpc_call_id ,
2010-07-20 21:26:36 +04:00
enum dcerpc_AuthType auth_type ,
2009-09-14 22:39:54 +04:00
enum dcerpc_AuthLevel auth_level ,
2005-09-30 21:13:37 +04:00
DATA_BLOB * pauth_blob ,
2010-07-15 07:31:38 +04:00
DATA_BLOB * rpc_out )
1998-03-12 00:11:04 +03:00
{
2010-07-08 21:30:50 +04:00
NTSTATUS status ;
union dcerpc_payload u ;
1999-12-13 16:27:58 +03:00
2010-07-08 21:30:50 +04:00
u . auth3 . _pad = 0 ;
1999-12-13 16:27:58 +03:00
2010-07-15 07:31:38 +04:00
status = dcerpc_push_dcerpc_auth ( mem_ctx ,
2010-07-20 21:26:36 +04:00
auth_type ,
2010-07-08 21:30:50 +04:00
auth_level ,
0 , /* auth_pad_length */
1 , /* auth_context_id */
pauth_blob ,
& u . auth3 . auth_info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2003-10-02 01:18:32 +04:00
}
1999-12-13 16:27:58 +03:00
2010-07-15 07:31:38 +04:00
status = dcerpc_push_ncacn_packet ( mem_ctx ,
2010-07-08 21:30:50 +04:00
DCERPC_PKT_AUTH3 ,
DCERPC_PFC_FLAG_FIRST |
DCERPC_PFC_FLAG_LAST ,
2010-07-13 00:27:22 +04:00
pauth_blob - > length ,
2010-07-08 21:30:50 +04:00
rpc_call_id ,
2010-07-11 20:18:13 +04:00
& u ,
2010-07-15 07:31:38 +04:00
rpc_out ) ;
data_blob_free ( & u . auth3 . auth_info ) ;
2010-07-08 21:30:50 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " create_bind_or_alt_ctx_internal: failed to marshall RPC_HDR_RB. \n " ) ) ;
return status ;
1998-10-09 03:57:46 +04:00
}
1998-03-12 00:11:04 +03:00
2005-09-30 21:13:37 +04:00
return NT_STATUS_OK ;
1999-12-13 16:27:58 +03:00
}
2005-09-30 21:13:37 +04:00
/*******************************************************************
Creates a DCE / RPC bind alter context authentication request which
may contain a spnego auth blobl
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
Jeremy requested that I get my NTLMSSP patch into CVS. He didn't request
the schannel code, but I've included that anyway. :-)
This patch revives the client-side NTLMSSP support for RPC named pipes
in Samba, and cleans up the client and server schannel code. The use of the
new code is enabled by the 'sign', 'seal' and 'schannel' commands in
rpcclient.
The aim was to prove that our separate NTLMSSP client library actually
implements NTLMSSP signing and sealing as per Microsoft's NTLMv1 implementation,
in the hope that knowing this will assist us in correctly implementing
NTLMSSP signing for SMB packets. (Still not yet functional)
This patch replaces the NTLMSSP implementation in rpc_client/cli_pipe.c with
calls to libsmb/ntlmssp.c. In the process, we have gained the ability to
use the more secure NT password, and the ability to sign-only, instead of
having to seal the pipe connection. (Previously we were limited to sealing,
and could only use the LM-password derived key).
Our new client-side NTLMSSP code also needed alteration to cope with our
comparatively simple server-side implementation. A future step is to replace
it with calls to the same NTLMSSP library.
Also included in this patch is the schannel 'sign only' patch I submitted to
the team earlier. While not enabled (and not functional, at this stage) the
work in this patch makes the code paths *much* easier to follow. I have also
included similar hooks in rpccleint to allow the use of schannel on *any* pipe.
rpcclient now defaults to not using schannel (or any other extra per-pipe
authenticiation) for any connection. The 'schannel' command enables schannel
for all pipes until disabled.
This code is also much more secure than the previous code, as changes to our
cli_pipe routines ensure that the authentication footer cannot be removed
by an attacker, and more error states are correctly handled.
(The same needs to be done to our server)
Andrew Bartlett
(This used to be commit 5472ddc9eaf4e79c5b2e1c8ee8c7f190dc285f19)
2003-07-14 12:46:32 +04:00
2010-07-15 07:31:38 +04:00
static NTSTATUS create_rpc_alter_context ( TALLOC_CTX * mem_ctx ,
2010-07-24 18:35:25 +04:00
enum dcerpc_AuthType auth_type ,
enum dcerpc_AuthLevel auth_level ,
2010-07-15 07:31:38 +04:00
uint32 rpc_call_id ,
2009-07-05 12:13:03 +04:00
const struct ndr_syntax_id * abstract ,
const struct ndr_syntax_id * transfer ,
2005-09-30 21:13:37 +04:00
const DATA_BLOB * pauth_blob , /* spnego auth blob already created. */
2010-07-15 07:31:38 +04:00
DATA_BLOB * rpc_out )
2005-09-30 21:13:37 +04:00
{
2009-03-25 01:56:42 +03:00
DATA_BLOB auth_info ;
NTSTATUS status ;
Jeremy requested that I get my NTLMSSP patch into CVS. He didn't request
the schannel code, but I've included that anyway. :-)
This patch revives the client-side NTLMSSP support for RPC named pipes
in Samba, and cleans up the client and server schannel code. The use of the
new code is enabled by the 'sign', 'seal' and 'schannel' commands in
rpcclient.
The aim was to prove that our separate NTLMSSP client library actually
implements NTLMSSP signing and sealing as per Microsoft's NTLMv1 implementation,
in the hope that knowing this will assist us in correctly implementing
NTLMSSP signing for SMB packets. (Still not yet functional)
This patch replaces the NTLMSSP implementation in rpc_client/cli_pipe.c with
calls to libsmb/ntlmssp.c. In the process, we have gained the ability to
use the more secure NT password, and the ability to sign-only, instead of
having to seal the pipe connection. (Previously we were limited to sealing,
and could only use the LM-password derived key).
Our new client-side NTLMSSP code also needed alteration to cope with our
comparatively simple server-side implementation. A future step is to replace
it with calls to the same NTLMSSP library.
Also included in this patch is the schannel 'sign only' patch I submitted to
the team earlier. While not enabled (and not functional, at this stage) the
work in this patch makes the code paths *much* easier to follow. I have also
included similar hooks in rpccleint to allow the use of schannel on *any* pipe.
rpcclient now defaults to not using schannel (or any other extra per-pipe
authenticiation) for any connection. The 'schannel' command enables schannel
for all pipes until disabled.
This code is also much more secure than the previous code, as changes to our
cli_pipe routines ensure that the authentication footer cannot be removed
by an attacker, and more error states are correctly handled.
(The same needs to be done to our server)
Andrew Bartlett
(This used to be commit 5472ddc9eaf4e79c5b2e1c8ee8c7f190dc285f19)
2003-07-14 12:46:32 +04:00
2010-07-15 07:31:38 +04:00
status = dcerpc_push_dcerpc_auth ( mem_ctx ,
2010-07-24 18:35:25 +04:00
auth_type ,
2009-03-25 01:56:42 +03:00
auth_level ,
0 , /* auth_pad_length */
1 , /* auth_context_id */
pauth_blob ,
& auth_info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
Jeremy requested that I get my NTLMSSP patch into CVS. He didn't request
the schannel code, but I've included that anyway. :-)
This patch revives the client-side NTLMSSP support for RPC named pipes
in Samba, and cleans up the client and server schannel code. The use of the
new code is enabled by the 'sign', 'seal' and 'schannel' commands in
rpcclient.
The aim was to prove that our separate NTLMSSP client library actually
implements NTLMSSP signing and sealing as per Microsoft's NTLMv1 implementation,
in the hope that knowing this will assist us in correctly implementing
NTLMSSP signing for SMB packets. (Still not yet functional)
This patch replaces the NTLMSSP implementation in rpc_client/cli_pipe.c with
calls to libsmb/ntlmssp.c. In the process, we have gained the ability to
use the more secure NT password, and the ability to sign-only, instead of
having to seal the pipe connection. (Previously we were limited to sealing,
and could only use the LM-password derived key).
Our new client-side NTLMSSP code also needed alteration to cope with our
comparatively simple server-side implementation. A future step is to replace
it with calls to the same NTLMSSP library.
Also included in this patch is the schannel 'sign only' patch I submitted to
the team earlier. While not enabled (and not functional, at this stage) the
work in this patch makes the code paths *much* easier to follow. I have also
included similar hooks in rpccleint to allow the use of schannel on *any* pipe.
rpcclient now defaults to not using schannel (or any other extra per-pipe
authenticiation) for any connection. The 'schannel' command enables schannel
for all pipes until disabled.
This code is also much more secure than the previous code, as changes to our
cli_pipe routines ensure that the authentication footer cannot be removed
by an attacker, and more error states are correctly handled.
(The same needs to be done to our server)
Andrew Bartlett
(This used to be commit 5472ddc9eaf4e79c5b2e1c8ee8c7f190dc285f19)
2003-07-14 12:46:32 +04:00
2010-07-15 07:31:38 +04:00
status = create_bind_or_alt_ctx_internal ( mem_ctx ,
DCERPC_PKT_ALTER ,
2009-03-25 01:56:42 +03:00
rpc_call_id ,
abstract ,
transfer ,
2010-07-15 07:31:38 +04:00
& auth_info ,
2014-01-04 01:41:33 +04:00
false , /* client_hdr_signing */
2010-07-15 07:31:38 +04:00
rpc_out ) ;
data_blob_free ( & auth_info ) ;
2009-03-25 01:56:42 +03:00
return status ;
2005-09-30 21:13:37 +04:00
}
1998-10-15 09:47:29 +04:00
2003-04-09 19:54:17 +04:00
/****************************************************************************
2005-09-30 21:13:37 +04:00
Do an rpc bind .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-04-09 19:54:17 +04:00
2009-01-18 14:12:15 +03:00
struct rpc_pipe_bind_state {
2013-02-18 12:57:22 +04:00
struct tevent_context * ev ;
2009-01-18 14:12:15 +03:00
struct rpc_pipe_client * cli ;
2010-07-15 07:31:38 +04:00
DATA_BLOB rpc_out ;
2010-09-07 22:52:58 +04:00
bool auth3 ;
2009-01-18 14:12:15 +03:00
uint32_t rpc_call_id ;
} ;
2009-03-24 00:33:00 +03:00
static void rpc_pipe_bind_step_one_done ( struct tevent_req * subreq ) ;
2010-07-24 18:35:25 +04:00
static NTSTATUS rpc_bind_next_send ( struct tevent_req * req ,
struct rpc_pipe_bind_state * state ,
DATA_BLOB * credentials ) ;
static NTSTATUS rpc_bind_finish_send ( struct tevent_req * req ,
struct rpc_pipe_bind_state * state ,
DATA_BLOB * credentials ) ;
2009-01-18 14:12:15 +03:00
2009-03-24 01:38:04 +03:00
struct tevent_req * rpc_pipe_bind_send ( TALLOC_CTX * mem_ctx ,
2013-02-18 12:57:22 +04:00
struct tevent_context * ev ,
2009-03-24 01:38:04 +03:00
struct rpc_pipe_client * cli ,
2010-07-18 00:58:50 +04:00
struct pipe_auth_data * auth )
2009-01-18 14:12:15 +03:00
{
2009-03-24 01:38:04 +03:00
struct tevent_req * req , * subreq ;
2009-01-18 14:12:15 +03:00
struct rpc_pipe_bind_state * state ;
NTSTATUS status ;
2009-03-24 01:38:04 +03:00
req = tevent_req_create ( mem_ctx , & state , struct rpc_pipe_bind_state ) ;
if ( req = = NULL ) {
2009-01-18 14:12:15 +03:00
return NULL ;
}
2010-09-03 19:03:49 +04:00
DEBUG ( 5 , ( " Bind RPC Pipe: %s auth_type %u, auth_level %u \n " ,
2009-11-03 12:59:18 +03:00
rpccli_pipe_txt ( talloc_tos ( ) , cli ) ,
2009-01-18 14:12:15 +03:00
( unsigned int ) auth - > auth_type ,
( unsigned int ) auth - > auth_level ) ) ;
state - > ev = ev ;
state - > cli = cli ;
state - > rpc_call_id = get_rpc_call_id ( ) ;
cli - > auth = talloc_move ( cli , & auth ) ;
/* Marshall the outgoing data. */
2010-07-15 07:31:38 +04:00
status = create_rpc_bind_req ( state , cli ,
2010-07-20 21:26:36 +04:00
cli - > auth ,
2009-01-18 14:12:15 +03:00
state - > rpc_call_id ,
& cli - > abstract_syntax ,
& cli - > transfer_syntax ,
2010-07-15 07:31:38 +04:00
& state - > rpc_out ) ;
2009-01-18 14:12:15 +03:00
2012-02-06 06:37:12 +04:00
if ( ! NT_STATUS_IS_OK ( status ) & &
! NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
2009-01-18 14:12:15 +03:00
goto post_status ;
}
subreq = rpc_api_pipe_send ( state , ev , cli , & state - > rpc_out ,
2013-10-18 01:44:35 +04:00
DCERPC_PKT_BIND_ACK , state - > rpc_call_id ) ;
2009-01-18 14:12:15 +03:00
if ( subreq = = NULL ) {
2009-03-24 00:33:00 +03:00
goto fail ;
2009-01-18 14:12:15 +03:00
}
2009-03-24 01:38:04 +03:00
tevent_req_set_callback ( subreq , rpc_pipe_bind_step_one_done , req ) ;
return req ;
2009-01-18 14:12:15 +03:00
post_status :
2009-03-24 01:38:04 +03:00
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
2009-03-24 00:33:00 +03:00
fail :
2009-03-24 01:38:04 +03:00
TALLOC_FREE ( req ) ;
2009-01-18 14:12:15 +03:00
return NULL ;
}
2009-03-24 00:33:00 +03:00
static void rpc_pipe_bind_step_one_done ( struct tevent_req * subreq )
2009-01-18 14:12:15 +03:00
{
2009-03-24 01:38:04 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct rpc_pipe_bind_state * state = tevent_req_data (
req , struct rpc_pipe_bind_state ) ;
2010-07-24 18:35:25 +04:00
struct pipe_auth_data * pauth = state - > cli - > auth ;
2011-10-27 16:50:37 +04:00
struct gensec_security * gensec_security ;
2011-01-21 17:51:05 +03:00
struct ncacn_packet * pkt = NULL ;
2010-07-21 20:12:58 +04:00
struct dcerpc_auth auth ;
2010-07-24 18:35:25 +04:00
DATA_BLOB auth_token = data_blob_null ;
2009-01-18 14:12:15 +03:00
NTSTATUS status ;
2010-09-07 22:51:38 +04:00
status = rpc_api_pipe_recv ( subreq , talloc_tos ( ) , & pkt , NULL ) ;
2009-01-18 14:12:15 +03:00
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " rpc_pipe_bind: %s bind request returned %s \n " ,
2009-11-03 12:59:18 +03:00
rpccli_pipe_txt ( talloc_tos ( ) , state - > cli ) ,
2009-01-18 14:12:15 +03:00
nt_errstr ( status ) ) ) ;
2009-03-24 01:38:04 +03:00
tevent_req_nterror ( req , status ) ;
2009-01-18 14:12:15 +03:00
return ;
}
2010-09-07 22:52:58 +04:00
if ( state - > auth3 ) {
tevent_req_done ( req ) ;
return ;
}
2010-07-13 16:49:35 +04:00
if ( ! check_bind_response ( & pkt - > u . bind_ack , & state - > cli - > transfer_syntax ) ) {
2009-01-18 14:12:15 +03:00
DEBUG ( 2 , ( " rpc_pipe_bind: check_bind_response failed. \n " ) ) ;
2009-03-24 01:38:04 +03:00
tevent_req_nterror ( req , NT_STATUS_BUFFER_TOO_SMALL ) ;
2009-01-18 14:12:15 +03:00
return ;
}
2010-07-13 16:49:35 +04:00
state - > cli - > max_xmit_frag = pkt - > u . bind_ack . max_xmit_frag ;
state - > cli - > max_recv_frag = pkt - > u . bind_ack . max_recv_frag ;
2009-01-18 14:12:15 +03:00
2010-08-03 13:11:28 +04:00
switch ( pauth - > auth_type ) {
2010-07-21 20:12:58 +04:00
case DCERPC_AUTH_TYPE_NONE :
2011-03-01 13:49:20 +03:00
case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM :
2010-07-21 20:12:58 +04:00
/* Bind complete. */
tevent_req_done ( req ) ;
return ;
2014-01-05 11:26:15 +04:00
case DCERPC_AUTH_TYPE_SCHANNEL :
2010-07-21 20:12:58 +04:00
case DCERPC_AUTH_TYPE_NTLMSSP :
case DCERPC_AUTH_TYPE_SPNEGO :
case DCERPC_AUTH_TYPE_KRB5 :
/* Paranoid lenght checks */
if ( pkt - > frag_length < DCERPC_AUTH_TRAILER_LENGTH
+ pkt - > auth_length ) {
tevent_req_nterror ( req ,
NT_STATUS_INFO_LENGTH_MISMATCH ) ;
return ;
}
/* get auth credentials */
status = dcerpc_pull_dcerpc_auth ( talloc_tos ( ) ,
& pkt - > u . bind_ack . auth_info ,
& auth , false ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Failed to pull dcerpc auth: %s. \n " ,
nt_errstr ( status ) ) ) ;
tevent_req_nterror ( req , status ) ;
return ;
}
break ;
default :
goto err_out ;
}
2009-01-18 14:12:15 +03:00
/*
* For authenticated binds we may need to do 3 or 4 leg binds .
*/
2010-08-03 13:11:28 +04:00
switch ( pauth - > auth_type ) {
2009-01-18 14:12:15 +03:00
2010-07-20 21:26:36 +04:00
case DCERPC_AUTH_TYPE_NONE :
2011-03-01 13:49:20 +03:00
case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM :
2009-01-18 14:12:15 +03:00
/* Bind complete. */
2009-03-24 01:38:04 +03:00
tevent_req_done ( req ) ;
2010-07-20 21:26:36 +04:00
return ;
2009-01-18 14:12:15 +03:00
2014-01-05 11:26:15 +04:00
case DCERPC_AUTH_TYPE_SCHANNEL :
2010-07-20 21:26:36 +04:00
case DCERPC_AUTH_TYPE_NTLMSSP :
2012-01-02 06:06:29 +04:00
case DCERPC_AUTH_TYPE_KRB5 :
2012-02-06 05:40:38 +04:00
case DCERPC_AUTH_TYPE_SPNEGO :
2011-10-27 16:50:37 +04:00
gensec_security = talloc_get_type_abort ( pauth - > auth_ctx ,
struct gensec_security ) ;
2014-01-04 01:41:33 +04:00
if ( pkt - > pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN ) {
if ( pauth - > client_hdr_signing ) {
pauth - > hdr_signing = true ;
gensec_want_feature ( gensec_security ,
GENSEC_FEATURE_SIGN_PKT_HEADER ) ;
}
}
2013-12-13 22:56:13 +04:00
status = gensec_update ( gensec_security , state ,
2011-10-18 14:13:16 +04:00
auth . credentials , & auth_token ) ;
2010-08-03 13:11:28 +04:00
if ( NT_STATUS_EQUAL ( status ,
NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
status = rpc_bind_next_send ( req , state ,
& auth_token ) ;
} else if ( NT_STATUS_IS_OK ( status ) ) {
2012-02-06 06:37:12 +04:00
if ( auth_token . length = = 0 ) {
/* Bind complete. */
tevent_req_done ( req ) ;
return ;
}
2010-08-03 13:11:28 +04:00
status = rpc_bind_finish_send ( req , state ,
& auth_token ) ;
}
2010-07-21 20:12:58 +04:00
break ;
2009-01-18 14:12:15 +03:00
default :
2010-07-21 20:12:58 +04:00
goto err_out ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
2009-01-18 14:12:15 +03:00
}
2010-07-21 20:12:58 +04:00
return ;
2010-07-20 21:26:36 +04:00
2010-07-21 20:12:58 +04:00
err_out :
2010-09-03 19:03:49 +04:00
DEBUG ( 0 , ( " cli_finish_bind_auth: unknown auth type %u \n " ,
( unsigned int ) state - > cli - > auth - > auth_type ) ) ;
2010-07-20 21:26:36 +04:00
tevent_req_nterror ( req , NT_STATUS_INTERNAL_ERROR ) ;
2009-01-18 14:12:15 +03:00
}
2010-07-24 18:35:25 +04:00
static NTSTATUS rpc_bind_next_send ( struct tevent_req * req ,
struct rpc_pipe_bind_state * state ,
DATA_BLOB * auth_token )
{
struct pipe_auth_data * auth = state - > cli - > auth ;
struct tevent_req * subreq ;
NTSTATUS status ;
/* Now prepare the alter context pdu. */
data_blob_free ( & state - > rpc_out ) ;
status = create_rpc_alter_context ( state ,
auth - > auth_type ,
auth - > auth_level ,
state - > rpc_call_id ,
& state - > cli - > abstract_syntax ,
& state - > cli - > transfer_syntax ,
auth_token ,
& state - > rpc_out ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
subreq = rpc_api_pipe_send ( state , state - > ev , state - > cli ,
2013-10-18 01:44:35 +04:00
& state - > rpc_out , DCERPC_PKT_ALTER_RESP ,
state - > rpc_call_id ) ;
2010-07-24 18:35:25 +04:00
if ( subreq = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
tevent_req_set_callback ( subreq , rpc_pipe_bind_step_one_done , req ) ;
return NT_STATUS_OK ;
}
static NTSTATUS rpc_bind_finish_send ( struct tevent_req * req ,
struct rpc_pipe_bind_state * state ,
DATA_BLOB * auth_token )
{
struct pipe_auth_data * auth = state - > cli - > auth ;
struct tevent_req * subreq ;
NTSTATUS status ;
2010-09-07 22:52:58 +04:00
state - > auth3 = true ;
2010-07-24 18:35:25 +04:00
/* Now prepare the auth3 context pdu. */
data_blob_free ( & state - > rpc_out ) ;
status = create_rpc_bind_auth3 ( state , state - > cli ,
state - > rpc_call_id ,
auth - > auth_type ,
auth - > auth_level ,
auth_token ,
& state - > rpc_out ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2010-09-07 22:52:58 +04:00
subreq = rpc_api_pipe_send ( state , state - > ev , state - > cli ,
2013-10-18 01:44:35 +04:00
& state - > rpc_out , DCERPC_PKT_AUTH3 ,
state - > rpc_call_id ) ;
2010-07-24 18:35:25 +04:00
if ( subreq = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2010-09-07 22:52:58 +04:00
tevent_req_set_callback ( subreq , rpc_pipe_bind_step_one_done , req ) ;
2010-07-24 18:35:25 +04:00
return NT_STATUS_OK ;
}
2009-03-24 01:38:04 +03:00
NTSTATUS rpc_pipe_bind_recv ( struct tevent_req * req )
2009-01-18 14:12:15 +03:00
{
2009-03-24 01:38:04 +03:00
return tevent_req_simple_recv_ntstatus ( req ) ;
2009-01-18 14:12:15 +03:00
}
NTSTATUS rpc_pipe_bind ( struct rpc_pipe_client * cli ,
2010-07-18 00:58:50 +04:00
struct pipe_auth_data * auth )
2009-01-18 14:12:15 +03:00
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2013-02-18 12:57:22 +04:00
struct tevent_context * ev ;
2009-03-24 01:38:04 +03:00
struct tevent_req * req ;
2009-04-06 22:52:04 +04:00
NTSTATUS status = NT_STATUS_OK ;
2009-01-18 14:12:15 +03:00
2013-02-18 12:17:45 +04:00
ev = samba_tevent_context_init ( frame ) ;
2009-01-18 14:12:15 +03:00
if ( ev = = NULL ) {
2009-04-06 22:52:04 +04:00
status = NT_STATUS_NO_MEMORY ;
2009-01-18 14:12:15 +03:00
goto fail ;
}
req = rpc_pipe_bind_send ( frame , ev , cli , auth ) ;
if ( req = = NULL ) {
2009-04-06 22:52:04 +04:00
status = NT_STATUS_NO_MEMORY ;
2009-01-18 14:12:15 +03:00
goto fail ;
}
2009-04-06 22:52:04 +04:00
if ( ! tevent_req_poll ( req , ev ) ) {
status = map_nt_error_from_unix ( errno ) ;
goto fail ;
}
2009-01-18 14:12:15 +03:00
status = rpc_pipe_bind_recv ( req ) ;
fail :
TALLOC_FREE ( frame ) ;
return status ;
}
2003-07-25 05:26:19 +04:00
2010-03-28 21:34:34 +04:00
# define RPCCLI_DEFAULT_TIMEOUT 10000 /* 10 seconds. */
2009-01-22 20:52:15 +03:00
unsigned int rpccli_set_timeout ( struct rpc_pipe_client * rpc_cli ,
2008-04-20 01:27:35 +04:00
unsigned int timeout )
{
2010-03-28 21:34:34 +04:00
unsigned int old ;
2010-03-25 17:51:51 +03:00
if ( rpc_cli - > transport = = NULL ) {
2010-03-28 21:34:34 +04:00
return RPCCLI_DEFAULT_TIMEOUT ;
2008-04-24 22:42:32 +04:00
}
2010-01-06 07:13:35 +03:00
2010-03-25 17:51:51 +03:00
if ( rpc_cli - > transport - > set_timeout = = NULL ) {
2010-03-28 21:34:34 +04:00
return RPCCLI_DEFAULT_TIMEOUT ;
}
old = rpc_cli - > transport - > set_timeout ( rpc_cli - > transport - > priv , timeout ) ;
if ( old = = 0 ) {
return RPCCLI_DEFAULT_TIMEOUT ;
2010-01-06 07:13:35 +03:00
}
2010-03-28 21:34:34 +04:00
return old ;
2008-04-20 16:05:25 +04:00
}
2010-03-25 17:00:38 +03:00
bool rpccli_is_connected ( struct rpc_pipe_client * rpc_cli )
{
if ( rpc_cli = = NULL ) {
return false ;
}
if ( rpc_cli - > transport = = NULL ) {
return false ;
}
return rpc_cli - > transport - > is_connected ( rpc_cli - > transport - > priv ) ;
}
2010-08-06 13:30:51 +04:00
struct rpccli_bh_state {
struct rpc_pipe_client * rpc_cli ;
} ;
static bool rpccli_bh_is_connected ( struct dcerpc_binding_handle * h )
{
struct rpccli_bh_state * hs = dcerpc_binding_handle_data ( h ,
struct rpccli_bh_state ) ;
return rpccli_is_connected ( hs - > rpc_cli ) ;
}
2010-09-03 21:59:15 +04:00
static uint32_t rpccli_bh_set_timeout ( struct dcerpc_binding_handle * h ,
uint32_t timeout )
{
struct rpccli_bh_state * hs = dcerpc_binding_handle_data ( h ,
struct rpccli_bh_state ) ;
return rpccli_set_timeout ( hs - > rpc_cli , timeout ) ;
}
2013-08-12 10:19:35 +04:00
static void rpccli_bh_auth_info ( struct dcerpc_binding_handle * h ,
enum dcerpc_AuthType * auth_type ,
enum dcerpc_AuthLevel * auth_level )
{
struct rpccli_bh_state * hs = dcerpc_binding_handle_data ( h ,
struct rpccli_bh_state ) ;
if ( hs - > rpc_cli = = NULL ) {
return ;
}
if ( hs - > rpc_cli - > auth = = NULL ) {
return ;
}
* auth_type = hs - > rpc_cli - > auth - > auth_type ;
* auth_level = hs - > rpc_cli - > auth - > auth_level ;
}
2010-08-06 13:30:51 +04:00
struct rpccli_bh_raw_call_state {
DATA_BLOB in_data ;
DATA_BLOB out_data ;
uint32_t out_flags ;
} ;
static void rpccli_bh_raw_call_done ( struct tevent_req * subreq ) ;
static struct tevent_req * rpccli_bh_raw_call_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct dcerpc_binding_handle * h ,
const struct GUID * object ,
uint32_t opnum ,
uint32_t in_flags ,
const uint8_t * in_data ,
size_t in_length )
{
struct rpccli_bh_state * hs = dcerpc_binding_handle_data ( h ,
struct rpccli_bh_state ) ;
struct tevent_req * req ;
struct rpccli_bh_raw_call_state * state ;
bool ok ;
struct tevent_req * subreq ;
req = tevent_req_create ( mem_ctx , & state ,
struct rpccli_bh_raw_call_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > in_data . data = discard_const_p ( uint8_t , in_data ) ;
state - > in_data . length = in_length ;
ok = rpccli_bh_is_connected ( h ) ;
if ( ! ok ) {
2011-09-14 19:56:30 +04:00
tevent_req_nterror ( req , NT_STATUS_CONNECTION_DISCONNECTED ) ;
2010-08-06 13:30:51 +04:00
return tevent_req_post ( req , ev ) ;
}
subreq = rpc_api_pipe_req_send ( state , ev , hs - > rpc_cli ,
opnum , & state - > in_data ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , rpccli_bh_raw_call_done , req ) ;
return req ;
}
static void rpccli_bh_raw_call_done ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct rpccli_bh_raw_call_state * state =
tevent_req_data ( req ,
struct rpccli_bh_raw_call_state ) ;
NTSTATUS status ;
state - > out_flags = 0 ;
/* TODO: support bigendian responses */
status = rpc_api_pipe_req_recv ( subreq , state , & state - > out_data ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return ;
}
tevent_req_done ( req ) ;
}
static NTSTATUS rpccli_bh_raw_call_recv ( struct tevent_req * req ,
TALLOC_CTX * mem_ctx ,
uint8_t * * out_data ,
size_t * out_length ,
uint32_t * out_flags )
{
struct rpccli_bh_raw_call_state * state =
tevent_req_data ( req ,
struct rpccli_bh_raw_call_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
return status ;
}
* out_data = talloc_move ( mem_ctx , & state - > out_data . data ) ;
* out_length = state - > out_data . length ;
* out_flags = state - > out_flags ;
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
}
struct rpccli_bh_disconnect_state {
uint8_t _dummy ;
} ;
static struct tevent_req * rpccli_bh_disconnect_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct dcerpc_binding_handle * h )
{
struct rpccli_bh_state * hs = dcerpc_binding_handle_data ( h ,
struct rpccli_bh_state ) ;
struct tevent_req * req ;
struct rpccli_bh_disconnect_state * state ;
bool ok ;
req = tevent_req_create ( mem_ctx , & state ,
struct rpccli_bh_disconnect_state ) ;
if ( req = = NULL ) {
return NULL ;
}
ok = rpccli_bh_is_connected ( h ) ;
if ( ! ok ) {
2011-09-14 19:56:30 +04:00
tevent_req_nterror ( req , NT_STATUS_CONNECTION_DISCONNECTED ) ;
2010-08-06 13:30:51 +04:00
return tevent_req_post ( req , ev ) ;
}
/*
* TODO : do a real async disconnect . . .
*
* For now the caller needs to free rpc_cli
*/
hs - > rpc_cli = NULL ;
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
static NTSTATUS rpccli_bh_disconnect_recv ( struct tevent_req * req )
{
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
return status ;
}
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
}
static bool rpccli_bh_ref_alloc ( struct dcerpc_binding_handle * h )
{
return true ;
}
static void rpccli_bh_do_ndr_print ( struct dcerpc_binding_handle * h ,
int ndr_flags ,
const void * _struct_ptr ,
const struct ndr_interface_call * call )
{
void * struct_ptr = discard_const ( _struct_ptr ) ;
if ( DEBUGLEVEL < 10 ) {
return ;
}
if ( ndr_flags & NDR_IN ) {
ndr_print_function_debug ( call - > ndr_print ,
call - > name ,
ndr_flags ,
struct_ptr ) ;
}
if ( ndr_flags & NDR_OUT ) {
ndr_print_function_debug ( call - > ndr_print ,
call - > name ,
ndr_flags ,
struct_ptr ) ;
}
}
static const struct dcerpc_binding_handle_ops rpccli_bh_ops = {
. name = " rpccli " ,
. is_connected = rpccli_bh_is_connected ,
2010-09-03 21:59:15 +04:00
. set_timeout = rpccli_bh_set_timeout ,
2013-08-12 10:19:35 +04:00
. auth_info = rpccli_bh_auth_info ,
2010-08-06 13:30:51 +04:00
. raw_call_send = rpccli_bh_raw_call_send ,
. raw_call_recv = rpccli_bh_raw_call_recv ,
. disconnect_send = rpccli_bh_disconnect_send ,
. disconnect_recv = rpccli_bh_disconnect_recv ,
. ref_alloc = rpccli_bh_ref_alloc ,
. do_ndr_print = rpccli_bh_do_ndr_print ,
} ;
/* initialise a rpc_pipe_client binding handle */
2013-08-27 15:23:04 +04:00
struct dcerpc_binding_handle * rpccli_bh_create ( struct rpc_pipe_client * c ,
const struct GUID * object ,
const struct ndr_interface_table * table )
2010-08-06 13:30:51 +04:00
{
struct dcerpc_binding_handle * h ;
struct rpccli_bh_state * hs ;
h = dcerpc_binding_handle_create ( c ,
& rpccli_bh_ops ,
2013-08-27 15:23:04 +04:00
object ,
table ,
2010-08-06 13:30:51 +04:00
& hs ,
struct rpccli_bh_state ,
__location__ ) ;
if ( h = = NULL ) {
return NULL ;
}
hs - > rpc_cli = c ;
return h ;
}
2011-03-01 13:49:20 +03:00
NTSTATUS rpccli_ncalrpc_bind_data ( TALLOC_CTX * mem_ctx ,
struct pipe_auth_data * * presult )
{
struct pipe_auth_data * result ;
2014-01-05 09:16:03 +04:00
result = talloc_zero ( mem_ctx , struct pipe_auth_data ) ;
2011-03-01 13:49:20 +03:00
if ( result = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
result - > auth_type = DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM ;
2011-03-21 11:29:14 +03:00
result - > auth_level = DCERPC_AUTH_LEVEL_CONNECT ;
2011-03-01 13:49:20 +03:00
result - > user_name = talloc_strdup ( result , " " ) ;
result - > domain = talloc_strdup ( result , " " ) ;
if ( ( result - > user_name = = NULL ) | | ( result - > domain = = NULL ) ) {
TALLOC_FREE ( result ) ;
return NT_STATUS_NO_MEMORY ;
}
* presult = result ;
return NT_STATUS_OK ;
}
2008-04-22 15:03:06 +04:00
NTSTATUS rpccli_anon_bind_data ( TALLOC_CTX * mem_ctx ,
2010-07-18 00:58:50 +04:00
struct pipe_auth_data * * presult )
2008-04-22 15:03:06 +04:00
{
2010-07-18 00:58:50 +04:00
struct pipe_auth_data * result ;
2008-04-22 15:03:06 +04:00
2014-01-05 09:16:03 +04:00
result = talloc_zero ( mem_ctx , struct pipe_auth_data ) ;
2008-04-22 15:03:06 +04:00
if ( result = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2010-07-20 21:26:36 +04:00
result - > auth_type = DCERPC_AUTH_TYPE_NONE ;
2009-09-14 22:39:54 +04:00
result - > auth_level = DCERPC_AUTH_LEVEL_NONE ;
2008-04-22 15:03:06 +04:00
result - > user_name = talloc_strdup ( result , " " ) ;
result - > domain = talloc_strdup ( result , " " ) ;
if ( ( result - > user_name = = NULL ) | | ( result - > domain = = NULL ) ) {
TALLOC_FREE ( result ) ;
return NT_STATUS_NO_MEMORY ;
}
* presult = result ;
return NT_STATUS_OK ;
}
2012-01-02 05:51:06 +04:00
static NTSTATUS rpccli_generic_bind_data ( TALLOC_CTX * mem_ctx ,
enum dcerpc_AuthType auth_type ,
enum dcerpc_AuthLevel auth_level ,
const char * server ,
const char * target_service ,
const char * domain ,
const char * username ,
const char * password ,
2012-02-06 05:40:38 +04:00
enum credentials_use_kerberos use_kerberos ,
2013-09-18 19:44:10 +04:00
struct netlogon_creds_CredentialState * creds ,
2012-01-02 05:51:06 +04:00
struct pipe_auth_data * * presult )
{
struct auth_generic_state * auth_generic_ctx ;
2010-07-18 00:58:50 +04:00
struct pipe_auth_data * result ;
2008-04-22 15:03:06 +04:00
NTSTATUS status ;
2014-01-05 09:16:03 +04:00
result = talloc_zero ( mem_ctx , struct pipe_auth_data ) ;
2008-04-22 15:03:06 +04:00
if ( result = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
result - > auth_type = auth_type ;
result - > auth_level = auth_level ;
result - > user_name = talloc_strdup ( result , username ) ;
result - > domain = talloc_strdup ( result , domain ) ;
if ( ( result - > user_name = = NULL ) | | ( result - > domain = = NULL ) ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
2011-12-27 03:25:55 +04:00
status = auth_generic_client_prepare ( result ,
2012-01-02 05:51:06 +04:00
& auth_generic_ctx ) ;
2008-04-22 15:03:06 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2012-01-02 05:51:06 +04:00
status = auth_generic_set_username ( auth_generic_ctx , username ) ;
2008-04-22 15:03:06 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2012-01-02 05:51:06 +04:00
status = auth_generic_set_domain ( auth_generic_ctx , domain ) ;
2008-04-22 15:03:06 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2012-01-02 05:51:06 +04:00
status = auth_generic_set_password ( auth_generic_ctx , password ) ;
2008-04-22 15:03:06 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2012-01-02 06:00:44 +04:00
status = gensec_set_target_service ( auth_generic_ctx - > gensec_security , target_service ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
status = gensec_set_target_hostname ( auth_generic_ctx - > gensec_security , server ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2012-02-06 05:40:38 +04:00
cli_credentials_set_kerberos_state ( auth_generic_ctx - > credentials , use_kerberos ) ;
2013-09-18 19:44:10 +04:00
cli_credentials_set_netlogon_creds ( auth_generic_ctx - > credentials , creds ) ;
2012-02-06 05:40:38 +04:00
2012-01-02 05:51:06 +04:00
status = auth_generic_client_start_by_authtype ( auth_generic_ctx , auth_type , auth_level ) ;
2011-10-17 13:19:11 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2012-01-02 05:51:06 +04:00
result - > auth_ctx = talloc_move ( result , & auth_generic_ctx - > gensec_security ) ;
talloc_free ( auth_generic_ctx ) ;
2008-04-22 15:03:06 +04:00
* presult = result ;
return NT_STATUS_OK ;
fail :
TALLOC_FREE ( result ) ;
return status ;
}
2008-05-20 20:08:41 +04:00
/**
* Create an rpc pipe client struct , connecting to a tcp port .
*/
2008-05-22 13:16:57 +04:00
static NTSTATUS rpc_pipe_open_tcp_port ( TALLOC_CTX * mem_ctx , const char * host ,
2012-11-23 21:15:30 +04:00
const struct sockaddr_storage * ss_addr ,
2008-05-22 13:16:57 +04:00
uint16_t port ,
2013-05-24 15:47:16 +04:00
const struct ndr_interface_table * table ,
2008-05-22 13:16:57 +04:00
struct rpc_pipe_client * * presult )
2008-04-25 00:24:20 +04:00
{
struct rpc_pipe_client * result ;
struct sockaddr_storage addr ;
NTSTATUS status ;
2009-01-22 20:52:15 +03:00
int fd ;
2008-04-25 00:24:20 +04:00
2011-06-07 05:44:43 +04:00
result = talloc_zero ( mem_ctx , struct rpc_pipe_client ) ;
2008-04-25 00:24:20 +04:00
if ( result = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2013-05-24 15:47:16 +04:00
result - > abstract_syntax = table - > syntax_id ;
2012-03-18 19:46:57 +04:00
result - > transfer_syntax = ndr_transfer_syntax_ndr ;
2008-04-25 00:24:20 +04:00
result - > desthost = talloc_strdup ( result , host ) ;
result - > srv_name_slash = talloc_asprintf_strupper_m (
result , " \\ \\ %s " , result - > desthost ) ;
if ( ( result - > desthost = = NULL ) | | ( result - > srv_name_slash = = NULL ) ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
result - > max_xmit_frag = RPC_MAX_PDU_FRAG_LEN ;
result - > max_recv_frag = RPC_MAX_PDU_FRAG_LEN ;
2012-11-23 21:15:30 +04:00
if ( ss_addr = = NULL ) {
if ( ! resolve_name ( host , & addr , NBT_NAME_SERVER , false ) ) {
status = NT_STATUS_NOT_FOUND ;
goto fail ;
}
} else {
addr = * ss_addr ;
2008-04-25 00:24:20 +04:00
}
2011-04-13 19:41:36 +04:00
status = open_socket_out ( & addr , port , 60 * 1000 , & fd ) ;
2009-01-03 21:50:05 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-04-25 00:24:20 +04:00
goto fail ;
}
2009-01-22 20:52:15 +03:00
set_socket_options ( fd , lp_socket_options ( ) ) ;
2008-04-25 00:24:20 +04:00
2009-01-22 20:52:15 +03:00
status = rpc_transport_sock_init ( result , fd , & result - > transport ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
close ( fd ) ;
goto fail ;
}
2008-05-20 20:25:42 +04:00
2009-09-10 21:59:37 +04:00
result - > transport - > transport = NCACN_IP_TCP ;
2013-08-27 15:23:04 +04:00
result - > binding_handle = rpccli_bh_create ( result , NULL , table ) ;
2010-08-06 13:30:51 +04:00
if ( result - > binding_handle = = NULL ) {
TALLOC_FREE ( result ) ;
return NT_STATUS_NO_MEMORY ;
}
2008-04-25 00:24:20 +04:00
* presult = result ;
return NT_STATUS_OK ;
fail :
TALLOC_FREE ( result ) ;
return status ;
}
2008-05-20 20:08:41 +04:00
/**
* Determine the tcp port on which a dcerpc interface is listening
* for the ncacn_ip_tcp transport via the endpoint mapper of the
* target host .
*/
2008-05-22 13:16:57 +04:00
static NTSTATUS rpc_pipe_get_tcp_port ( const char * host ,
2012-11-23 21:15:30 +04:00
const struct sockaddr_storage * addr ,
2013-05-24 15:46:07 +04:00
const struct ndr_interface_table * table ,
2008-05-22 13:16:57 +04:00
uint16_t * pport )
2008-05-20 20:08:41 +04:00
{
NTSTATUS status ;
struct rpc_pipe_client * epm_pipe = NULL ;
2011-01-04 15:32:28 +03:00
struct dcerpc_binding_handle * epm_handle = NULL ;
2010-07-18 00:58:50 +04:00
struct pipe_auth_data * auth = NULL ;
2008-05-20 20:08:41 +04:00
struct dcerpc_binding * map_binding = NULL ;
struct dcerpc_binding * res_binding = NULL ;
2014-01-30 12:26:26 +04:00
enum dcerpc_transport_t transport ;
const char * endpoint = NULL ;
2008-05-20 20:08:41 +04:00
struct epm_twr_t * map_tower = NULL ;
struct epm_twr_t * res_towers = NULL ;
struct policy_handle * entry_handle = NULL ;
uint32_t num_towers = 0 ;
uint32_t max_towers = 1 ;
struct epm_twr_p_t towers ;
TALLOC_CTX * tmp_ctx = talloc_stackframe ( ) ;
2011-01-04 15:32:28 +03:00
uint32_t result = 0 ;
2008-05-20 20:08:41 +04:00
if ( pport = = NULL ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto done ;
}
2013-05-24 15:46:07 +04:00
if ( ndr_syntax_id_equal ( & table - > syntax_id ,
2011-03-08 18:33:50 +03:00
& ndr_table_epmapper . syntax_id ) ) {
* pport = 135 ;
2013-11-01 11:54:27 +04:00
status = NT_STATUS_OK ;
goto done ;
2011-03-08 18:33:50 +03:00
}
2008-05-20 20:08:41 +04:00
/* open the connection to the endpoint mapper */
2012-11-23 21:15:30 +04:00
status = rpc_pipe_open_tcp_port ( tmp_ctx , host , addr , 135 ,
2013-05-24 15:47:16 +04:00
& ndr_table_epmapper ,
2008-05-20 20:08:41 +04:00
& epm_pipe ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
2011-01-04 15:32:28 +03:00
epm_handle = epm_pipe - > binding_handle ;
2008-05-20 20:08:41 +04:00
status = rpccli_anon_bind_data ( tmp_ctx , & auth ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
status = rpc_pipe_bind ( epm_pipe , auth ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
/* create tower for asking the epmapper */
2014-01-30 12:26:26 +04:00
status = dcerpc_parse_binding ( tmp_ctx , " ncacn_ip_tcp:[135] " ,
& map_binding ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-05-20 20:08:41 +04:00
goto done ;
}
2014-01-30 12:26:26 +04:00
status = dcerpc_binding_set_abstract_syntax ( map_binding ,
& table - > syntax_id ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
2008-05-20 20:08:41 +04:00
2011-06-07 05:44:43 +04:00
map_tower = talloc_zero ( tmp_ctx , struct epm_twr_t ) ;
2008-05-20 20:08:41 +04:00
if ( map_tower = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
status = dcerpc_binding_build_tower ( tmp_ctx , map_binding ,
& ( map_tower - > tower ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
/* allocate further parameters for the epm_Map call */
2011-06-07 05:30:12 +04:00
res_towers = talloc_array ( tmp_ctx , struct epm_twr_t , max_towers ) ;
2008-05-20 20:08:41 +04:00
if ( res_towers = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
towers . twr = res_towers ;
2011-06-07 05:44:43 +04:00
entry_handle = talloc_zero ( tmp_ctx , struct policy_handle ) ;
2008-05-20 20:08:41 +04:00
if ( entry_handle = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
/* ask the endpoint mapper for the port */
2011-01-04 15:32:28 +03:00
status = dcerpc_epm_Map ( epm_handle ,
2008-05-20 20:08:41 +04:00
tmp_ctx ,
2011-05-05 21:41:59 +04:00
discard_const_p ( struct GUID ,
2013-05-24 15:46:07 +04:00
& ( table - > syntax_id . uuid ) ) ,
2008-05-20 20:08:41 +04:00
map_tower ,
entry_handle ,
max_towers ,
& num_towers ,
2011-01-04 15:32:28 +03:00
& towers ,
& result ) ;
2008-05-20 20:08:41 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
2011-01-04 15:32:28 +03:00
if ( result ! = EPMAPPER_STATUS_OK ) {
status = NT_STATUS_UNSUCCESSFUL ;
goto done ;
}
2008-05-20 20:08:41 +04:00
if ( num_towers ! = 1 ) {
status = NT_STATUS_UNSUCCESSFUL ;
goto done ;
}
/* extract the port from the answer */
status = dcerpc_binding_from_tower ( tmp_ctx ,
& ( towers . twr - > tower ) ,
& res_binding ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
2014-01-30 12:26:26 +04:00
transport = dcerpc_binding_get_transport ( res_binding ) ;
endpoint = dcerpc_binding_get_string_option ( res_binding , " endpoint " ) ;
2008-05-20 20:08:41 +04:00
/* are further checks here necessary? */
2014-01-30 12:26:26 +04:00
if ( transport ! = NCACN_IP_TCP ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto done ;
}
if ( endpoint = = NULL ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
2008-05-20 20:08:41 +04:00
goto done ;
}
2014-01-30 12:26:26 +04:00
* pport = ( uint16_t ) atoi ( endpoint ) ;
2008-05-20 20:08:41 +04:00
done :
TALLOC_FREE ( tmp_ctx ) ;
return status ;
}
/**
* Create a rpc pipe client struct , connecting to a host via tcp .
* The port is determined by asking the endpoint mapper on the given
* host .
*/
NTSTATUS rpc_pipe_open_tcp ( TALLOC_CTX * mem_ctx , const char * host ,
2012-11-23 21:15:30 +04:00
const struct sockaddr_storage * addr ,
2013-05-24 15:44:00 +04:00
const struct ndr_interface_table * table ,
2008-05-20 20:08:41 +04:00
struct rpc_pipe_client * * presult )
{
NTSTATUS status ;
2008-05-23 17:09:21 +04:00
uint16_t port = 0 ;
2008-05-20 20:08:41 +04:00
2013-05-24 15:46:07 +04:00
status = rpc_pipe_get_tcp_port ( host , addr , table , & port ) ;
2008-05-20 20:08:41 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-11-13 00:59:25 +03:00
return status ;
2008-05-20 20:08:41 +04:00
}
2012-11-23 21:15:30 +04:00
return rpc_pipe_open_tcp_port ( mem_ctx , host , addr , port ,
2013-05-24 15:47:16 +04:00
table , presult ) ;
2008-05-20 20:08:41 +04:00
}
2008-05-13 01:37:07 +04:00
/********************************************************************
Create a rpc pipe client struct , connecting to a unix domain socket
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS rpc_pipe_open_ncalrpc ( TALLOC_CTX * mem_ctx , const char * socket_path ,
2013-05-17 18:16:59 +04:00
const struct ndr_interface_table * table ,
2008-05-13 01:37:07 +04:00
struct rpc_pipe_client * * presult )
{
struct rpc_pipe_client * result ;
struct sockaddr_un addr ;
NTSTATUS status ;
2009-01-22 20:52:15 +03:00
int fd ;
2012-03-24 17:57:47 +04:00
socklen_t salen ;
2008-05-13 01:37:07 +04:00
2008-07-20 12:40:43 +04:00
result = talloc_zero ( mem_ctx , struct rpc_pipe_client ) ;
2008-05-13 01:37:07 +04:00
if ( result = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2013-05-17 18:16:59 +04:00
result - > abstract_syntax = table - > syntax_id ;
2012-03-18 19:46:57 +04:00
result - > transfer_syntax = ndr_transfer_syntax_ndr ;
2008-05-13 01:37:07 +04:00
2009-02-13 12:56:34 +03:00
result - > desthost = get_myname ( result ) ;
2008-05-13 01:37:07 +04:00
result - > srv_name_slash = talloc_asprintf_strupper_m (
result , " \\ \\ %s " , result - > desthost ) ;
if ( ( result - > desthost = = NULL ) | | ( result - > srv_name_slash = = NULL ) ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
result - > max_xmit_frag = RPC_MAX_PDU_FRAG_LEN ;
result - > max_recv_frag = RPC_MAX_PDU_FRAG_LEN ;
2009-01-22 20:52:15 +03:00
fd = socket ( AF_UNIX , SOCK_STREAM , 0 ) ;
if ( fd = = - 1 ) {
2008-05-13 01:37:07 +04:00
status = map_nt_error_from_unix ( errno ) ;
goto fail ;
}
ZERO_STRUCT ( addr ) ;
addr . sun_family = AF_UNIX ;
2011-04-22 11:34:35 +04:00
strlcpy ( addr . sun_path , socket_path , sizeof ( addr . sun_path ) ) ;
2012-03-24 17:57:47 +04:00
salen = sizeof ( struct sockaddr_un ) ;
2008-05-13 01:37:07 +04:00
2012-03-24 17:57:47 +04:00
if ( connect ( fd , ( struct sockaddr * ) ( void * ) & addr , salen ) = = - 1 ) {
2008-05-13 01:37:07 +04:00
DEBUG ( 0 , ( " connect(%s) failed: %s \n " , socket_path ,
strerror ( errno ) ) ) ;
2009-01-22 20:52:15 +03:00
close ( fd ) ;
2008-05-13 01:37:07 +04:00
return map_nt_error_from_unix ( errno ) ;
}
2009-01-22 20:52:15 +03:00
status = rpc_transport_sock_init ( result , fd , & result - > transport ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
close ( fd ) ;
goto fail ;
}
2009-09-10 21:59:37 +04:00
result - > transport - > transport = NCALRPC ;
2013-08-27 15:23:04 +04:00
result - > binding_handle = rpccli_bh_create ( result , NULL , table ) ;
2010-08-06 13:30:51 +04:00
if ( result - > binding_handle = = NULL ) {
TALLOC_FREE ( result ) ;
return NT_STATUS_NO_MEMORY ;
}
2008-05-13 01:37:07 +04:00
* presult = result ;
return NT_STATUS_OK ;
fail :
TALLOC_FREE ( result ) ;
return status ;
}
2010-03-29 16:58:19 +04:00
struct rpc_pipe_client_np_ref {
2009-01-22 20:52:15 +03:00
struct cli_state * cli ;
2010-03-29 16:58:19 +04:00
struct rpc_pipe_client * pipe ;
} ;
2009-01-22 20:52:15 +03:00
2010-03-29 16:58:19 +04:00
static int rpc_pipe_client_np_ref_destructor ( struct rpc_pipe_client_np_ref * np_ref )
{
DLIST_REMOVE ( np_ref - > cli - > pipe_list , np_ref - > pipe ) ;
2009-01-22 20:52:15 +03:00
return 0 ;
}
2008-04-25 00:24:20 +04:00
2005-09-30 21:13:37 +04:00
/****************************************************************************
Open a named pipe over SMB to a remote server .
2005-12-14 07:00:58 +03:00
*
* CAVEAT CALLER OF THIS FUNCTION :
* The returned rpc_pipe_client saves a copy of the cli_state cli pointer ,
* so be sure that this function is called AFTER any structure ( vs pointer )
* assignment of the cli . In particular , libsmbclient does structure
* assignments of cli , which invalidates the data in the returned
* rpc_pipe_client if this function is called before the structure assignment
* of cli .
*
2005-09-30 21:13:37 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-01-02 08:39:49 +03:00
2008-07-20 12:56:36 +04:00
static NTSTATUS rpc_pipe_open_np ( struct cli_state * cli ,
2013-05-24 15:40:45 +04:00
const struct ndr_interface_table * table ,
2008-07-20 12:56:36 +04:00
struct rpc_pipe_client * * presult )
2005-06-09 02:10:34 +04:00
{
struct rpc_pipe_client * result ;
2009-01-22 20:52:15 +03:00
NTSTATUS status ;
2010-03-29 16:58:19 +04:00
struct rpc_pipe_client_np_ref * np_ref ;
2005-06-09 02:10:34 +04:00
2006-03-15 17:58:39 +03:00
/* sanity check to protect against crashes */
if ( ! cli ) {
2008-07-20 12:56:36 +04:00
return NT_STATUS_INVALID_HANDLE ;
2006-03-15 17:58:39 +03:00
}
2011-06-07 05:44:43 +04:00
result = talloc_zero ( NULL , struct rpc_pipe_client ) ;
2005-09-30 21:13:37 +04:00
if ( result = = NULL ) {
2008-07-20 12:56:36 +04:00
return NT_STATUS_NO_MEMORY ;
2005-09-30 21:13:37 +04:00
}
2005-06-09 02:10:34 +04:00
2013-05-24 15:40:45 +04:00
result - > abstract_syntax = table - > syntax_id ;
2012-03-18 19:46:57 +04:00
result - > transfer_syntax = ndr_transfer_syntax_ndr ;
2012-05-19 19:31:50 +04:00
result - > desthost = talloc_strdup ( result , smbXcli_conn_remote_name ( cli - > conn ) ) ;
2008-04-20 01:03:16 +04:00
result - > srv_name_slash = talloc_asprintf_strupper_m (
result , " \\ \\ %s " , result - > desthost ) ;
2008-04-20 14:19:27 +04:00
2009-01-14 14:58:13 +03:00
result - > max_xmit_frag = RPC_MAX_PDU_FRAG_LEN ;
result - > max_recv_frag = RPC_MAX_PDU_FRAG_LEN ;
2008-04-22 16:31:35 +04:00
if ( ( result - > desthost = = NULL ) | | ( result - > srv_name_slash = = NULL ) ) {
2008-04-20 01:03:16 +04:00
TALLOC_FREE ( result ) ;
2008-07-20 12:56:36 +04:00
return NT_STATUS_NO_MEMORY ;
2008-04-20 01:03:16 +04:00
}
2013-05-24 15:52:05 +04:00
status = rpc_transport_np_init ( result , cli , table ,
2009-01-22 20:52:15 +03:00
& result - > transport ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-07-20 12:56:36 +04:00
TALLOC_FREE ( result ) ;
2009-01-22 20:52:15 +03:00
return status ;
2008-04-20 14:19:27 +04:00
}
2009-09-10 21:59:37 +04:00
result - > transport - > transport = NCACN_NP ;
2010-03-29 16:58:19 +04:00
np_ref = talloc ( result - > transport , struct rpc_pipe_client_np_ref ) ;
if ( np_ref = = NULL ) {
TALLOC_FREE ( result ) ;
return NT_STATUS_NO_MEMORY ;
}
np_ref - > cli = cli ;
np_ref - > pipe = result ;
DLIST_ADD ( np_ref - > cli - > pipe_list , np_ref - > pipe ) ;
talloc_set_destructor ( np_ref , rpc_pipe_client_np_ref_destructor ) ;
2008-04-20 15:51:46 +04:00
2013-08-27 15:23:04 +04:00
result - > binding_handle = rpccli_bh_create ( result , NULL , table ) ;
2010-08-06 13:30:51 +04:00
if ( result - > binding_handle = = NULL ) {
TALLOC_FREE ( result ) ;
return NT_STATUS_NO_MEMORY ;
}
2008-07-20 12:56:36 +04:00
* presult = result ;
return NT_STATUS_OK ;
2005-06-09 02:10:34 +04:00
}
2008-05-24 03:29:13 +04:00
/****************************************************************************
Open a pipe to a remote server .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-20 13:04:31 +04:00
static NTSTATUS cli_rpc_pipe_open ( struct cli_state * cli ,
2008-11-04 20:40:24 +03:00
enum dcerpc_transport_t transport ,
2013-05-24 15:38:01 +04:00
const struct ndr_interface_table * table ,
2008-07-20 13:04:31 +04:00
struct rpc_pipe_client * * presult )
2008-05-24 03:29:13 +04:00
{
2008-11-04 20:40:24 +03:00
switch ( transport ) {
case NCACN_IP_TCP :
2012-11-23 21:15:30 +04:00
return rpc_pipe_open_tcp ( NULL ,
smbXcli_conn_remote_name ( cli - > conn ) ,
smbXcli_conn_remote_sockaddr ( cli - > conn ) ,
2013-05-24 15:44:00 +04:00
table , presult ) ;
2008-11-04 20:40:24 +03:00
case NCACN_NP :
2013-05-24 15:40:45 +04:00
return rpc_pipe_open_np ( cli , table , presult ) ;
2008-11-04 20:40:24 +03:00
default :
return NT_STATUS_NOT_IMPLEMENTED ;
2008-05-24 03:29:13 +04:00
}
}
2005-09-30 21:13:37 +04:00
/****************************************************************************
Open a named pipe to an SMB server and bind anonymously .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-11-04 20:40:24 +03:00
NTSTATUS cli_rpc_pipe_open_noauth_transport ( struct cli_state * cli ,
enum dcerpc_transport_t transport ,
2013-05-24 15:33:03 +04:00
const struct ndr_interface_table * table ,
2008-11-04 20:40:24 +03:00
struct rpc_pipe_client * * presult )
2005-06-09 02:10:34 +04:00
{
struct rpc_pipe_client * result ;
2010-07-18 00:58:50 +04:00
struct pipe_auth_data * auth ;
2008-07-20 13:04:31 +04:00
NTSTATUS status ;
2005-06-09 02:10:34 +04:00
2013-05-24 15:38:01 +04:00
status = cli_rpc_pipe_open ( cli , transport , table , & result ) ;
2008-07-20 13:04:31 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2005-09-30 21:13:37 +04:00
}
2005-06-09 02:10:34 +04:00
2008-07-20 13:04:31 +04:00
status = rpccli_anon_bind_data ( result , & auth ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-04-22 16:31:35 +04:00
DEBUG ( 0 , ( " rpccli_anon_bind_data returned %s \n " ,
2008-07-20 13:04:31 +04:00
nt_errstr ( status ) ) ) ;
2008-04-22 16:31:35 +04:00
TALLOC_FREE ( result ) ;
2008-07-20 13:04:31 +04:00
return status ;
2008-04-22 16:31:35 +04:00
}
2008-04-22 20:17:01 +04:00
/*
* This is a bit of an abstraction violation due to the fact that an
* anonymous bind on an authenticated SMB inherits the user / domain
* from the enclosing SMB creds
*/
TALLOC_FREE ( auth - > user_name ) ;
TALLOC_FREE ( auth - > domain ) ;
auth - > user_name = talloc_strdup ( auth , cli - > user_name ) ;
auth - > domain = talloc_strdup ( auth , cli - > domain ) ;
2012-08-01 12:18:22 +04:00
if ( transport = = NCACN_NP ) {
struct smbXcli_session * session ;
if ( smbXcli_conn_protocol ( cli - > conn ) > = PROTOCOL_SMB2_02 ) {
session = cli - > smb2 . session ;
} else {
session = cli - > smb1 . session ;
}
status = smbXcli_session_application_key ( session , auth ,
2012-08-01 13:00:02 +04:00
& auth - > transport_session_key ) ;
2012-08-01 12:18:22 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2012-08-01 13:00:02 +04:00
auth - > transport_session_key = data_blob_null ;
2012-08-01 12:18:22 +04:00
}
}
2008-04-22 20:17:01 +04:00
if ( ( auth - > user_name = = NULL ) | | ( auth - > domain = = NULL ) ) {
TALLOC_FREE ( result ) ;
2008-07-20 13:04:31 +04:00
return NT_STATUS_NO_MEMORY ;
2008-04-22 20:17:01 +04:00
}
2008-07-20 13:04:31 +04:00
status = rpc_pipe_bind ( result , auth ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2007-02-16 16:30:19 +03:00
int lvl = 0 ;
2013-05-24 15:33:03 +04:00
if ( ndr_syntax_id_equal ( & table - > syntax_id ,
2008-07-20 13:04:31 +04:00
& ndr_table_dssetup . syntax_id ) ) {
2007-02-16 16:30:19 +03:00
/* non AD domains just don't have this pipe, avoid
* level 0 statement in that case - gd */
lvl = 3 ;
}
2008-07-20 13:04:31 +04:00
DEBUG ( lvl , ( " cli_rpc_pipe_open_noauth: rpc_pipe_bind for pipe "
" %s failed with error %s \n " ,
2013-08-08 19:40:22 +04:00
table - > name ,
2008-07-20 13:04:31 +04:00
nt_errstr ( status ) ) ) ;
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( result ) ;
2008-07-20 13:04:31 +04:00
return status ;
2005-06-09 02:10:34 +04:00
}
2008-04-24 22:42:32 +04:00
DEBUG ( 10 , ( " cli_rpc_pipe_open_noauth: opened pipe %s to machine "
2009-01-22 20:52:15 +03:00
" %s and bound anonymously. \n " ,
2013-08-08 19:40:22 +04:00
table - > name ,
2011-07-22 18:43:27 +04:00
result - > desthost ) ) ;
2005-09-30 21:13:37 +04:00
2008-07-20 13:04:31 +04:00
* presult = result ;
return NT_STATUS_OK ;
2005-06-09 02:10:34 +04:00
}
2008-11-04 20:40:24 +03:00
/****************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_rpc_pipe_open_noauth ( struct cli_state * cli ,
2013-05-24 15:29:28 +04:00
const struct ndr_interface_table * table ,
2008-11-04 20:40:24 +03:00
struct rpc_pipe_client * * presult )
{
return cli_rpc_pipe_open_noauth_transport ( cli , NCACN_NP ,
2013-05-24 15:33:03 +04:00
table , presult ) ;
2008-11-04 20:40:24 +03:00
}
2005-09-30 21:13:37 +04:00
/****************************************************************************
2012-01-02 05:51:06 +04:00
Open a named pipe to an SMB server and bind using the mech specified
2005-09-30 21:13:37 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-01-02 05:51:06 +04:00
NTSTATUS cli_rpc_pipe_open_generic_auth ( struct cli_state * cli ,
2012-01-10 14:53:42 +04:00
const struct ndr_interface_table * table ,
2012-01-02 05:51:06 +04:00
enum dcerpc_transport_t transport ,
enum dcerpc_AuthType auth_type ,
enum dcerpc_AuthLevel auth_level ,
const char * server ,
const char * domain ,
const char * username ,
const char * password ,
struct rpc_pipe_client * * presult )
2005-06-09 02:10:34 +04:00
{
struct rpc_pipe_client * result ;
2010-08-03 17:55:20 +04:00
struct pipe_auth_data * auth = NULL ;
2012-01-10 14:53:42 +04:00
const char * target_service = table - > authservices - > names [ 0 ] ;
2012-02-06 05:40:38 +04:00
2008-07-20 13:04:31 +04:00
NTSTATUS status ;
2005-06-09 02:10:34 +04:00
2013-05-24 15:38:01 +04:00
status = cli_rpc_pipe_open ( cli , transport , table , & result ) ;
2008-07-20 13:04:31 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2005-09-30 21:13:37 +04:00
}
2008-04-20 18:23:48 +04:00
2012-01-02 05:51:06 +04:00
status = rpccli_generic_bind_data ( result ,
2010-07-30 03:55:44 +04:00
auth_type , auth_level ,
2012-01-02 05:51:06 +04:00
server , target_service ,
2012-02-06 05:40:38 +04:00
domain , username , password ,
CRED_AUTO_USE_KERBEROS ,
2013-09-18 19:44:10 +04:00
NULL ,
2010-07-20 21:26:36 +04:00
& auth ) ;
2008-07-20 13:04:31 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2012-01-02 05:51:06 +04:00
DEBUG ( 0 , ( " rpccli_generic_bind_data returned %s \n " ,
2008-07-20 13:04:31 +04:00
nt_errstr ( status ) ) ) ;
goto err ;
2005-09-30 21:13:37 +04:00
}
2008-04-20 18:23:48 +04:00
2008-07-20 13:04:31 +04:00
status = rpc_pipe_bind ( result , auth ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2012-01-02 05:51:06 +04:00
DEBUG ( 0 , ( " cli_rpc_pipe_open_generic_auth: cli_rpc_pipe_bind failed with error %s \n " ,
2008-07-20 13:04:31 +04:00
nt_errstr ( status ) ) ) ;
2005-09-30 21:13:37 +04:00
goto err ;
}
2012-01-02 05:51:06 +04:00
DEBUG ( 10 , ( " cli_rpc_pipe_open_generic_auth: opened pipe %s to "
2012-01-10 14:53:42 +04:00
" machine %s and bound as user %s \\ %s. \n " , table - > name ,
2011-07-22 18:43:27 +04:00
result - > desthost , domain , username ) ) ;
2005-09-30 21:13:37 +04:00
2008-07-20 13:04:31 +04:00
* presult = result ;
return NT_STATUS_OK ;
2005-09-30 21:13:37 +04:00
err :
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( result ) ;
2008-07-20 13:04:31 +04:00
return status ;
2005-06-09 02:10:34 +04:00
}
2005-09-30 21:13:37 +04:00
/****************************************************************************
External interface .
Open a named pipe to an SMB server and bind using schannel ( bind type 68 )
using session_key . sign and seal .
2009-04-20 18:50:49 +04:00
The * pdc will be stolen onto this new pipe
2005-09-30 21:13:37 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-20 13:04:31 +04:00
NTSTATUS cli_rpc_pipe_open_schannel_with_key ( struct cli_state * cli ,
2013-05-24 15:17:24 +04:00
const struct ndr_interface_table * table ,
2009-09-11 00:32:34 +04:00
enum dcerpc_transport_t transport ,
2008-07-20 13:04:31 +04:00
const char * domain ,
2013-07-27 13:30:13 +04:00
struct netlogon_creds_cli_context * netlogon_creds ,
2013-04-25 21:43:58 +04:00
struct rpc_pipe_client * * _rpccli )
2005-06-09 02:10:34 +04:00
{
2013-04-25 21:43:58 +04:00
struct rpc_pipe_client * rpccli ;
struct pipe_auth_data * rpcauth ;
2013-07-27 13:30:13 +04:00
struct netlogon_creds_CredentialState * creds = NULL ;
2013-10-17 19:03:00 +04:00
enum dcerpc_AuthLevel auth_level ;
2008-07-20 13:04:31 +04:00
NTSTATUS status ;
2013-09-18 20:33:14 +04:00
const char * target_service = table - > authservices - > names [ 0 ] ;
2013-07-27 13:30:13 +04:00
int rpc_pipe_bind_dbglvl = 0 ;
2005-06-09 02:10:34 +04:00
2013-04-25 21:43:58 +04:00
status = cli_rpc_pipe_open ( cli , transport , table , & rpccli ) ;
2008-07-20 13:04:31 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2005-09-30 21:13:37 +04:00
}
2013-07-27 13:30:13 +04:00
status = netlogon_creds_cli_lock ( netlogon_creds , rpccli , & creds ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " netlogon_creds_cli_get returned %s \n " ,
nt_errstr ( status ) ) ) ;
TALLOC_FREE ( rpccli ) ;
return status ;
}
2013-10-17 19:03:00 +04:00
auth_level = netlogon_creds_cli_auth_level ( netlogon_creds ) ;
2013-09-18 20:33:14 +04:00
status = rpccli_generic_bind_data ( rpccli ,
DCERPC_AUTH_TYPE_SCHANNEL ,
auth_level ,
NULL ,
target_service ,
domain ,
2013-07-27 13:30:13 +04:00
creds - > computer_name ,
2013-09-18 20:33:14 +04:00
NULL ,
CRED_AUTO_USE_KERBEROS ,
2013-07-27 13:30:13 +04:00
creds ,
2013-09-18 20:33:14 +04:00
& rpcauth ) ;
2008-07-20 13:04:31 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2013-09-18 20:33:14 +04:00
DEBUG ( 0 , ( " rpccli_generic_bind_data returned %s \n " ,
2008-07-20 13:04:31 +04:00
nt_errstr ( status ) ) ) ;
2013-04-25 21:43:58 +04:00
TALLOC_FREE ( rpccli ) ;
2008-07-20 13:04:31 +04:00
return status ;
2005-09-30 21:13:37 +04:00
}
2013-04-25 21:43:58 +04:00
status = rpc_pipe_bind ( rpccli , rpcauth ) ;
2013-07-27 13:30:13 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NETWORK_ACCESS_DENIED ) ) {
rpc_pipe_bind_dbglvl = 1 ;
netlogon_creds_cli_delete ( netlogon_creds , & creds ) ;
}
2008-07-20 13:04:31 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2013-07-27 13:30:13 +04:00
DEBUG ( rpc_pipe_bind_dbglvl ,
( " cli_rpc_pipe_open_schannel_with_key: "
" rpc_pipe_bind failed with error %s \n " ,
nt_errstr ( status ) ) ) ;
2013-04-25 21:43:58 +04:00
TALLOC_FREE ( rpccli ) ;
2008-07-20 13:04:31 +04:00
return status ;
2005-06-09 02:10:34 +04:00
}
2013-07-27 13:30:13 +04:00
TALLOC_FREE ( creds ) ;
2013-04-25 21:34:13 +04:00
2013-07-27 13:30:13 +04:00
if ( ! ndr_syntax_id_equal ( & table - > syntax_id , & ndr_table_netlogon . syntax_id ) ) {
2013-04-25 21:34:13 +04:00
goto done ;
}
2013-07-27 13:30:13 +04:00
status = netlogon_creds_cli_check ( netlogon_creds ,
rpccli - > binding_handle ) ;
2013-04-25 21:34:13 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2013-07-27 13:30:13 +04:00
DEBUG ( 0 , ( " netlogon_creds_cli_check failed with %s \n " ,
2013-04-25 21:34:13 +04:00
nt_errstr ( status ) ) ) ;
TALLOC_FREE ( rpccli ) ;
return status ;
}
done :
2005-09-30 21:13:37 +04:00
DEBUG ( 10 , ( " cli_rpc_pipe_open_schannel_with_key: opened pipe %s to machine %s "
2009-01-22 20:52:15 +03:00
" for domain %s and bound using schannel. \n " ,
2013-08-08 19:40:22 +04:00
table - > name ,
2013-04-25 21:43:58 +04:00
rpccli - > desthost , domain ) ) ;
2005-09-30 21:13:37 +04:00
2013-04-25 21:43:58 +04:00
* _rpccli = rpccli ;
2008-07-20 13:04:31 +04:00
return NT_STATUS_OK ;
2005-06-09 02:10:34 +04:00
}
2012-01-10 14:03:02 +04:00
NTSTATUS cli_rpc_pipe_open_spnego ( struct cli_state * cli ,
2012-01-10 14:53:42 +04:00
const struct ndr_interface_table * table ,
2012-01-10 14:03:02 +04:00
enum dcerpc_transport_t transport ,
const char * oid ,
enum dcerpc_AuthLevel auth_level ,
const char * server ,
const char * domain ,
const char * username ,
const char * password ,
struct rpc_pipe_client * * presult )
2010-07-30 03:55:44 +04:00
{
struct rpc_pipe_client * result ;
2012-02-06 05:40:38 +04:00
struct pipe_auth_data * auth = NULL ;
2012-01-10 14:53:42 +04:00
const char * target_service = table - > authservices - > names [ 0 ] ;
2012-02-06 05:40:38 +04:00
NTSTATUS status ;
enum credentials_use_kerberos use_kerberos ;
if ( strcmp ( oid , GENSEC_OID_KERBEROS5 ) = = 0 ) {
use_kerberos = CRED_MUST_USE_KERBEROS ;
} else if ( strcmp ( oid , GENSEC_OID_NTLMSSP ) = = 0 ) {
use_kerberos = CRED_DONT_USE_KERBEROS ;
} else {
return NT_STATUS_INVALID_PARAMETER ;
}
2010-07-30 03:55:44 +04:00
2013-05-24 15:38:01 +04:00
status = cli_rpc_pipe_open ( cli , transport , table , & result ) ;
2010-07-30 03:55:44 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2012-02-06 05:40:38 +04:00
status = rpccli_generic_bind_data ( result ,
DCERPC_AUTH_TYPE_SPNEGO , auth_level ,
server , target_service ,
domain , username , password ,
2013-09-18 19:44:10 +04:00
use_kerberos , NULL ,
2012-02-06 05:40:38 +04:00
& auth ) ;
2010-07-30 03:55:44 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2012-02-06 05:40:38 +04:00
DEBUG ( 0 , ( " rpccli_generic_bind_data returned %s \n " ,
2010-07-30 03:55:44 +04:00
nt_errstr ( status ) ) ) ;
2012-02-06 05:40:38 +04:00
goto err ;
2010-07-30 03:55:44 +04:00
}
status = rpc_pipe_bind ( result , auth ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2012-02-06 05:40:38 +04:00
DEBUG ( 0 , ( " cli_rpc_pipe_open_spnego: cli_rpc_pipe_bind failed with error %s \n " ,
nt_errstr ( status ) ) ) ;
goto err ;
2010-07-30 03:55:44 +04:00
}
2012-02-06 05:40:38 +04:00
DEBUG ( 10 , ( " cli_rpc_pipe_open_spnego: opened pipe %s to "
" machine %s. \n " , table - > name ,
result - > desthost ) ) ;
2010-07-30 03:55:44 +04:00
* presult = result ;
return NT_STATUS_OK ;
2012-02-06 05:40:38 +04:00
err :
2010-07-30 03:55:44 +04:00
TALLOC_FREE ( result ) ;
return status ;
}
2008-06-25 02:21:37 +04:00
NTSTATUS cli_get_session_key ( TALLOC_CTX * mem_ctx ,
struct rpc_pipe_client * cli ,
2008-06-10 23:35:34 +04:00
DATA_BLOB * session_key )
{
2011-10-18 14:55:24 +04:00
NTSTATUS status ;
2011-03-16 23:50:59 +03:00
struct pipe_auth_data * a ;
2011-10-27 16:50:37 +04:00
struct gensec_security * gensec_security ;
2010-08-02 20:05:45 +04:00
DATA_BLOB sk = data_blob_null ;
2010-08-17 15:06:13 +04:00
bool make_dup = false ;
2010-07-18 00:58:50 +04:00
2008-06-10 23:35:34 +04:00
if ( ! session_key | | ! cli ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2011-03-16 23:50:59 +03:00
a = cli - > auth ;
if ( a = = NULL ) {
2008-06-10 23:35:34 +04:00
return NT_STATUS_INVALID_PARAMETER ;
}
switch ( cli - > auth - > auth_type ) {
2010-07-20 21:26:36 +04:00
case DCERPC_AUTH_TYPE_SPNEGO :
case DCERPC_AUTH_TYPE_NTLMSSP :
2012-01-02 06:06:29 +04:00
case DCERPC_AUTH_TYPE_KRB5 :
2011-10-27 16:50:37 +04:00
gensec_security = talloc_get_type_abort ( a - > auth_ctx ,
struct gensec_security ) ;
status = gensec_session_key ( gensec_security , mem_ctx , & sk ) ;
2011-10-18 14:55:24 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2011-08-02 04:24:28 +04:00
make_dup = false ;
2010-07-19 23:43:22 +04:00
break ;
2011-03-01 13:49:20 +03:00
case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM :
2010-07-20 21:26:36 +04:00
case DCERPC_AUTH_TYPE_NONE :
2012-08-01 13:00:02 +04:00
sk = data_blob_const ( a - > transport_session_key . data ,
a - > transport_session_key . length ) ;
2010-08-02 20:05:45 +04:00
make_dup = true ;
2010-07-19 23:43:22 +04:00
break ;
default :
2010-08-02 20:05:45 +04:00
break ;
}
if ( ! sk . data ) {
2010-07-19 23:43:22 +04:00
return NT_STATUS_NO_USER_SESSION_KEY ;
2008-06-10 23:35:34 +04:00
}
2010-08-02 20:05:45 +04:00
if ( make_dup ) {
2011-07-07 16:50:47 +04:00
* session_key = data_blob_dup_talloc ( mem_ctx , sk ) ;
2010-08-02 20:05:45 +04:00
} else {
* session_key = sk ;
}
2008-06-10 23:35:34 +04:00
return NT_STATUS_OK ;
}