diff options
Diffstat (limited to 'source/rpc_client/cli_pipe.c')
-rw-r--r-- | source/rpc_client/cli_pipe.c | 1886 |
1 files changed, 584 insertions, 1302 deletions
diff --git a/source/rpc_client/cli_pipe.c b/source/rpc_client/cli_pipe.c index 41dde87c42..35256d713b 100644 --- a/source/rpc_client/cli_pipe.c +++ b/source/rpc_client/cli_pipe.c @@ -18,88 +18,11 @@ */ #include "includes.h" -#include "librpc/gen_ndr/cli_epmapper.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_CLI -/******************************************************************* -interface/version dce/rpc pipe identification -********************************************************************/ - -#define PIPE_SRVSVC "\\PIPE\\srvsvc" -#define PIPE_SAMR "\\PIPE\\samr" -#define PIPE_WINREG "\\PIPE\\winreg" -#define PIPE_WKSSVC "\\PIPE\\wkssvc" -#define PIPE_NETLOGON "\\PIPE\\NETLOGON" -#define PIPE_NTLSA "\\PIPE\\ntlsa" -#define PIPE_NTSVCS "\\PIPE\\ntsvcs" -#define PIPE_LSASS "\\PIPE\\lsass" -#define PIPE_LSARPC "\\PIPE\\lsarpc" -#define PIPE_SPOOLSS "\\PIPE\\spoolss" -#define PIPE_NETDFS "\\PIPE\\netdfs" -#define PIPE_ECHO "\\PIPE\\rpcecho" -#define PIPE_SHUTDOWN "\\PIPE\\initshutdown" -#define PIPE_EPM "\\PIPE\\epmapper" -#define PIPE_SVCCTL "\\PIPE\\svcctl" -#define PIPE_EVENTLOG "\\PIPE\\eventlog" -#define PIPE_EPMAPPER "\\PIPE\\epmapper" -#define PIPE_DRSUAPI "\\PIPE\\drsuapi" - -/* - * IMPORTANT!! If you update this structure, make sure to - * update the index #defines in smb.h. - */ - -static const struct pipe_id_info { - /* the names appear not to matter: the syntaxes _do_ matter */ - - const char *client_pipe; - const RPC_IFACE *abstr_syntax; /* this one is the abstract syntax id */ -} pipe_names [] = -{ - { PIPE_LSARPC, &ndr_table_lsarpc.syntax_id }, - { PIPE_LSARPC, &ndr_table_dssetup.syntax_id }, - { PIPE_SAMR, &ndr_table_samr.syntax_id }, - { PIPE_NETLOGON, &ndr_table_netlogon.syntax_id }, - { PIPE_SRVSVC, &ndr_table_srvsvc.syntax_id }, - { PIPE_WKSSVC, &ndr_table_wkssvc.syntax_id }, - { PIPE_WINREG, &ndr_table_winreg.syntax_id }, - { PIPE_SPOOLSS, &syntax_spoolss }, - { PIPE_NETDFS, &ndr_table_netdfs.syntax_id }, - { PIPE_ECHO, &ndr_table_rpcecho.syntax_id }, - { PIPE_SHUTDOWN, &ndr_table_initshutdown.syntax_id }, - { PIPE_SVCCTL, &ndr_table_svcctl.syntax_id }, - { PIPE_EVENTLOG, &ndr_table_eventlog.syntax_id }, - { PIPE_NTSVCS, &ndr_table_ntsvcs.syntax_id }, - { PIPE_EPMAPPER, &ndr_table_epmapper.syntax_id }, - { PIPE_DRSUAPI, &ndr_table_drsuapi.syntax_id }, - { NULL, NULL } -}; - -/**************************************************************************** - Return the pipe name from the interface. - ****************************************************************************/ - -const char *cli_get_pipe_name_from_iface(TALLOC_CTX *mem_ctx, - struct cli_state *cli, - const struct ndr_syntax_id *interface) -{ - int i; - for (i = 0; pipe_names[i].client_pipe; i++) { - if (ndr_syntax_id_equal(pipe_names[i].abstr_syntax, - interface)) { - return &pipe_names[i].client_pipe[5]; - } - } - - /* - * Here we should ask \\epmapper, but for now our code is only - * interested in the known pipes mentioned in pipe_names[] - */ - - return NULL; -} +extern struct pipe_id_info pipe_names[]; /******************************************************************** Map internal value to wire value. @@ -135,34 +58,6 @@ static int map_pipe_auth_type_to_rpc_auth_type(enum pipe_auth_type auth_type) } /******************************************************************** - Pipe description for a DEBUG - ********************************************************************/ -static char *rpccli_pipe_txt(TALLOC_CTX *mem_ctx, struct rpc_pipe_client *cli) -{ - char *result; - - switch (cli->transport_type) { - case NCACN_NP: - result = talloc_asprintf(mem_ctx, "host %s, pipe %s, " - "fnum 0x%x", - cli->desthost, - cli->trans.np.pipe_name, - (unsigned int)(cli->trans.np.fnum)); - break; - case NCACN_IP_TCP: - case NCACN_UNIX_STREAM: - result = talloc_asprintf(mem_ctx, "host %s, fd %d", - cli->desthost, cli->trans.sock.fd); - break; - default: - result = talloc_asprintf(mem_ctx, "host %s", cli->desthost); - break; - } - SMB_ASSERT(result != NULL); - return result; -} - -/******************************************************************** Rpc pipe call id. ********************************************************************/ @@ -173,58 +68,6 @@ static uint32 get_rpc_call_id(void) } /******************************************************************* - Read from a RPC named pipe - ********************************************************************/ -static NTSTATUS rpc_read_np(struct cli_state *cli, const char *pipe_name, - int fnum, char *buf, off_t offset, size_t size, - ssize_t *pnum_read) -{ - ssize_t num_read; - - num_read = cli_read(cli, fnum, buf, offset, size); - - DEBUG(5,("rpc_read_np: num_read = %d, read offset: %u, to read: %u\n", - (int)num_read, (unsigned int)offset, (unsigned int)size)); - - /* - * A dos error of ERRDOS/ERRmoredata is not an error. - */ - if (cli_is_dos_error(cli)) { - uint32 ecode; - uint8 eclass; - cli_dos_error(cli, &eclass, &ecode); - if (eclass != ERRDOS && ecode != ERRmoredata) { - DEBUG(0,("rpc_read: DOS Error %d/%u (%s) in cli_read " - "on fnum 0x%x\n", eclass, (unsigned int)ecode, - cli_errstr(cli), fnum)); - return dos_to_ntstatus(eclass, ecode); - } - } - - /* - * Likewise for NT_STATUS_BUFFER_TOO_SMALL - */ - if (cli_is_nt_error(cli)) { - if (!NT_STATUS_EQUAL(cli_nt_error(cli), - NT_STATUS_BUFFER_TOO_SMALL)) { - DEBUG(0,("rpc_read: Error (%s) in cli_read on fnum " - "0x%x\n", nt_errstr(cli_nt_error(cli)), fnum)); - return cli_nt_error(cli); - } - } - - if (num_read == -1) { - DEBUG(0,("rpc_read: Error - cli_read on fnum 0x%x returned " - "-1\n", fnum)); - return cli_get_nt_error(cli); - } - - *pnum_read = num_read; - return NT_STATUS_OK; -} - - -/******************************************************************* Use SMBreadX to get rest of one fragment's worth of rpc data. Will expand the current_pdu struct to the correct size. ********************************************************************/ @@ -236,7 +79,7 @@ static NTSTATUS rpc_read(struct rpc_pipe_client *cli, { size_t size = (size_t)cli->max_recv_frag; uint32 stream_offset = 0; - ssize_t num_read = 0; + ssize_t num_read; char *pdata; ssize_t extra_data_size = ((ssize_t)*current_pdu_offset) + ((ssize_t)data_to_read) - (ssize_t)prs_data_size(current_pdu); @@ -258,36 +101,49 @@ static NTSTATUS rpc_read(struct rpc_pipe_client *cli, pdata = prs_data_p(current_pdu) + *current_pdu_offset; do { - NTSTATUS status; - /* read data using SMBreadX */ if (size > (size_t)data_to_read) { size = (size_t)data_to_read; } - switch (cli->transport_type) { - case NCACN_NP: - status = rpc_read_np(cli->trans.np.cli, - cli->trans.np.pipe_name, - cli->trans.np.fnum, pdata, - (off_t)stream_offset, size, - &num_read); - break; - case NCACN_IP_TCP: - case NCACN_UNIX_STREAM: - status = NT_STATUS_OK; - num_read = sys_read(cli->trans.sock.fd, pdata, size); - if (num_read == -1) { - status = map_nt_error_from_unix(errno); + num_read = cli_read(cli->cli, cli->fnum, pdata, + (off_t)stream_offset, size); + + DEBUG(5,("rpc_read: num_read = %d, read offset: %u, to read: %u\n", + (int)num_read, (unsigned int)stream_offset, (unsigned int)data_to_read)); + + /* + * A dos error of ERRDOS/ERRmoredata is not an error. + */ + if (cli_is_dos_error(cli->cli)) { + uint32 ecode; + uint8 eclass; + cli_dos_error(cli->cli, &eclass, &ecode); + if (eclass != ERRDOS && ecode != ERRmoredata) { + DEBUG(0,("rpc_read: DOS Error %d/%u (%s) in cli_read on pipe %s\n", + eclass, (unsigned int)ecode, + cli_errstr(cli->cli), + cli->pipe_name )); + return dos_to_ntstatus(eclass, ecode); } - if (num_read == 0) { - status = NT_STATUS_END_OF_FILE; + } + + /* + * Likewise for NT_STATUS_BUFFER_TOO_SMALL + */ + if (cli_is_nt_error(cli->cli)) { + if (!NT_STATUS_EQUAL(cli_nt_error(cli->cli), NT_STATUS_BUFFER_TOO_SMALL)) { + DEBUG(0,("rpc_read: Error (%s) in cli_read on pipe %s\n", + nt_errstr(cli_nt_error(cli->cli)), + cli->pipe_name )); + return cli_nt_error(cli->cli); } - break; - default: - DEBUG(0, ("unknown transport type %d\n", - cli->transport_type)); - return NT_STATUS_INTERNAL_ERROR; + } + + if (num_read == -1) { + DEBUG(0,("rpc_read: Error - cli_read on pipe %s returned -1\n", + cli->pipe_name )); + return cli_get_nt_error(cli->cli); } data_to_read -= num_read; @@ -359,7 +215,7 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, RPC_HDR *pr RPC_HDR_AUTH auth_info; uint32 save_offset = prs_offset(current_pdu); uint32 auth_len = prhdr->auth_len; - NTLMSSP_STATE *ntlmssp_state = cli->auth->a_u.ntlmssp_state; + NTLMSSP_STATE *ntlmssp_state = cli->auth.a_u.ntlmssp_state; unsigned char *data = NULL; size_t data_len; unsigned char *full_packet_data = NULL; @@ -367,8 +223,7 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, RPC_HDR *pr DATA_BLOB auth_blob; NTSTATUS status; - if (cli->auth->auth_level == PIPE_AUTH_LEVEL_NONE - || cli->auth->auth_level == PIPE_AUTH_LEVEL_CONNECT) { + if (cli->auth.auth_level == PIPE_AUTH_LEVEL_NONE || cli->auth.auth_level == PIPE_AUTH_LEVEL_CONNECT) { return NT_STATUS_OK; } @@ -412,7 +267,7 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, RPC_HDR *pr auth_blob.data = (unsigned char *)prs_data_p(current_pdu) + prs_offset(current_pdu); auth_blob.length = auth_len; - switch (cli->auth->auth_level) { + switch (cli->auth.auth_level) { case PIPE_AUTH_LEVEL_PRIVACY: /* Data is encrypted. */ status = ntlmssp_unseal_packet(ntlmssp_state, @@ -422,8 +277,11 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, RPC_HDR *pr &auth_blob); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("cli_pipe_verify_ntlmssp: failed to unseal " - "packet from %s. Error was %s.\n", - rpccli_pipe_txt(debug_ctx(), cli), + "packet from remote machine %s on pipe %s " + "fnum 0x%x. Error was %s.\n", + cli->cli->desthost, + cli->pipe_name, + (unsigned int)cli->fnum, nt_errstr(status) )); return status; } @@ -437,15 +295,18 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, RPC_HDR *pr &auth_blob); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("cli_pipe_verify_ntlmssp: check signing failed on " - "packet from %s. Error was %s.\n", - rpccli_pipe_txt(debug_ctx(), cli), + "packet from remote machine %s on pipe %s " + "fnum 0x%x. Error was %s.\n", + cli->cli->desthost, + cli->pipe_name, + (unsigned int)cli->fnum, nt_errstr(status) )); return status; } break; default: - DEBUG(0, ("cli_pipe_verify_ntlmssp: unknown internal " - "auth level %d\n", cli->auth->auth_level)); + DEBUG(0,("cli_pipe_verify_ntlmssp: unknown internal auth level %d\n", + cli->auth.auth_level )); return NT_STATUS_INVALID_INFO_CLASS; } @@ -481,12 +342,10 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *p RPC_AUTH_SCHANNEL_CHK schannel_chk; uint32 auth_len = prhdr->auth_len; uint32 save_offset = prs_offset(current_pdu); - struct schannel_auth_struct *schannel_auth = - cli->auth->a_u.schannel_auth; + struct schannel_auth_struct *schannel_auth = cli->auth.a_u.schannel_auth; uint32 data_len; - if (cli->auth->auth_level == PIPE_AUTH_LEVEL_NONE - || cli->auth->auth_level == PIPE_AUTH_LEVEL_CONNECT) { + if (cli->auth.auth_level == PIPE_AUTH_LEVEL_NONE || cli->auth.auth_level == PIPE_AUTH_LEVEL_CONNECT) { return NT_STATUS_OK; } @@ -514,7 +373,7 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *p (unsigned int)RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len )); return NT_STATUS_BUFFER_TOO_SMALL; } - + if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, current_pdu, 0)) { DEBUG(0,("cli_pipe_verify_schannel: failed to unmarshall RPC_HDR_AUTH.\n")); return NT_STATUS_BUFFER_TOO_SMALL; @@ -533,14 +392,17 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *p } if (!schannel_decode(schannel_auth, - cli->auth->auth_level, + cli->auth.auth_level, SENDER_IS_ACCEPTOR, &schannel_chk, prs_data_p(current_pdu)+RPC_HEADER_LEN+RPC_HDR_RESP_LEN, data_len)) { DEBUG(3,("cli_pipe_verify_schannel: failed to decode PDU " - "Connection to %s.\n", - rpccli_pipe_txt(debug_ctx(), cli))); + "Connection to remote machine %s " + "pipe %s fnum 0x%x.\n", + cli->cli->desthost, + cli->pipe_name, + (unsigned int)cli->fnum )); return NT_STATUS_INVALID_PARAMETER; } @@ -594,13 +456,14 @@ static NTSTATUS cli_pipe_validate_rpc_response(struct rpc_pipe_client *cli, RPC_ * Now we have a complete RPC request PDU fragment, try and verify any auth data. */ - switch(cli->auth->auth_type) { + switch(cli->auth.auth_type) { case PIPE_AUTH_TYPE_NONE: if (prhdr->auth_len) { - DEBUG(3, ("cli_pipe_validate_rpc_response: " - "Connection to %s - got non-zero " - "auth len %u.\n", - rpccli_pipe_txt(debug_ctx(), cli), + DEBUG(3, ("cli_pipe_validate_rpc_response: Connection to remote machine %s " + "pipe %s fnum 0x%x - got non-zero auth len %u.\n", + cli->cli->desthost, + cli->pipe_name, + (unsigned int)cli->fnum, (unsigned int)prhdr->auth_len )); return NT_STATUS_INVALID_PARAMETER; } @@ -624,10 +487,12 @@ static NTSTATUS cli_pipe_validate_rpc_response(struct rpc_pipe_client *cli, RPC_ case PIPE_AUTH_TYPE_KRB5: case PIPE_AUTH_TYPE_SPNEGO_KRB5: default: - DEBUG(3, ("cli_pipe_validate_rpc_response: Connection " - "to %s - unknown internal auth type %u.\n", - rpccli_pipe_txt(debug_ctx(), cli), - cli->auth->auth_type )); + DEBUG(3, ("cli_pipe_validate_rpc_response: Connection to remote machine %s " + "pipe %s fnum %x - unknown internal auth type %u.\n", + cli->cli->desthost, + cli->pipe_name, + (unsigned int)cli->fnum, + cli->auth.auth_type )); return NT_STATUS_INVALID_INFO_CLASS; } @@ -728,9 +593,11 @@ static NTSTATUS cli_pipe_validate_current_pdu(struct rpc_pipe_client *cli, RPC_H } case RPC_BINDNACK: - DEBUG(1, ("cli_pipe_validate_current_pdu: Bind NACK " - "received from %s!\n", - rpccli_pipe_txt(debug_ctx(), cli))); + DEBUG(1, ("cli_pipe_validate_current_pdu: Bind NACK received from remote machine %s " + "pipe %s fnum 0x%x!\n", + cli->cli->desthost, + cli->pipe_name, + (unsigned int)cli->fnum)); /* Use this for now... */ return NT_STATUS_NETWORK_ACCESS_DENIED; @@ -749,29 +616,37 @@ static NTSTATUS cli_pipe_validate_current_pdu(struct rpc_pipe_client *cli, RPC_H return NT_STATUS_BUFFER_TOO_SMALL; } - DEBUG(1, ("cli_pipe_validate_current_pdu: RPC fault " - "code %s received from %s!\n", + DEBUG(1, ("cli_pipe_validate_current_pdu: RPC fault code %s received from remote machine %s " + "pipe %s fnum 0x%x!\n", dcerpc_errstr(NT_STATUS_V(fault_resp.status)), - rpccli_pipe_txt(debug_ctx(), cli))); + cli->cli->desthost, + cli->pipe_name, + (unsigned int)cli->fnum)); if (NT_STATUS_IS_OK(fault_resp.status)) { return NT_STATUS_UNSUCCESSFUL; } else { return fault_resp.status; } + } default: DEBUG(0, ("cli_pipe_validate_current_pdu: unknown packet type %u received " - "from %s!\n", + "from remote machine %s pipe %s fnum 0x%x!\n", (unsigned int)prhdr->pkt_type, - rpccli_pipe_txt(debug_ctx(), cli))); + cli->cli->desthost, + cli->pipe_name, + (unsigned int)cli->fnum)); return NT_STATUS_INVALID_INFO_CLASS; } if (prhdr->pkt_type != expected_pkt_type) { - DEBUG(3, ("cli_pipe_validate_current_pdu: Connection to %s " - "got an unexpected RPC packet type - %u, not %u\n", - rpccli_pipe_txt(debug_ctx(), cli), + DEBUG(3, ("cli_pipe_validate_current_pdu: Connection to remote machine %s " + "pipe %s fnum %x got an unexpected RPC packet " + "type - %u, not %u\n", + cli->cli->desthost, + cli->pipe_name, + (unsigned int)cli->fnum, prhdr->pkt_type, expected_pkt_type)); return NT_STATUS_INVALID_INFO_CLASS; @@ -867,6 +742,7 @@ static NTSTATUS rpc_api_pipe(struct rpc_pipe_client *cli, NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; char *rparam = NULL; uint32 rparam_len = 0; + uint16 setup[2]; char *pdata = prs_data_p(data); uint32 data_len = prs_offset(data); char *prdata = NULL; @@ -874,7 +750,7 @@ static NTSTATUS rpc_api_pipe(struct rpc_pipe_client *cli, uint32 max_data = cli->max_xmit_frag ? cli->max_xmit_frag : RPC_MAX_PDU_FRAG_LEN; uint32 current_rbuf_offset = 0; prs_struct current_pdu; - + #ifdef DEVELOPER /* Ensure we're not sending too much. */ SMB_ASSERT(data_len <= max_data); @@ -883,73 +759,38 @@ static NTSTATUS rpc_api_pipe(struct rpc_pipe_client *cli, /* Set up the current pdu parse struct. */ prs_init_empty(¤t_pdu, prs_get_mem_context(rbuf), UNMARSHALL); - DEBUG(5,("rpc_api_pipe: %s\n", rpccli_pipe_txt(debug_ctx(), cli))); + /* Create setup parameters - must be in native byte order. */ + setup[0] = TRANSACT_DCERPCCMD; + setup[1] = cli->fnum; /* Pipe file handle. */ - switch (cli->transport_type) { - case NCACN_NP: { - uint16 setup[2]; - /* Create setup parameters - must be in native byte order. */ - setup[0] = TRANSACT_DCERPCCMD; - setup[1] = cli->trans.np.fnum; /* Pipe file handle. */ + DEBUG(5,("rpc_api_pipe: Remote machine %s pipe %s fnum 0x%x\n", + cli->cli->desthost, + cli->pipe_name, + (unsigned int)cli->fnum )); - /* - * Send the last (or only) fragment of an RPC request. For - * small amounts of data (about 1024 bytes or so) the RPC - * request and response appears in a SMBtrans request and - * response. - */ + /* + * Send the last (or only) fragment of an RPC request. For small + * amounts of data (about 1024 bytes or so) the RPC request and response + * appears in a SMBtrans request and response. + */ - if (!cli_api_pipe(cli->trans.np.cli, "\\PIPE\\", - setup, 2, 0, /* Setup, length, max */ - NULL, 0, 0, /* Params, length, max */ - pdata, data_len, max_data, /* data, length, - * max */ - &rparam, &rparam_len, /* return params, - * len */ - &prdata, &rdata_len)) /* return data, len */ - { - DEBUG(0, ("rpc_api_pipe: %s returned critical error. " - "Error was %s\n", - rpccli_pipe_txt(debug_ctx(), cli), - cli_errstr(cli->trans.np.cli))); - ret = cli_get_nt_error(cli->trans.np.cli); - SAFE_FREE(rparam); - SAFE_FREE(prdata); - goto err; - } - break; - } - case NCACN_IP_TCP: - case NCACN_UNIX_STREAM: + if (!cli_api_pipe(cli->cli, "\\PIPE\\", + setup, 2, 0, /* Setup, length, max */ + NULL, 0, 0, /* Params, length, max */ + pdata, data_len, max_data, /* data, length, max */ + &rparam, &rparam_len, /* return params, len */ + &prdata, &rdata_len)) /* return data, len */ { - ssize_t nwritten, nread; - nwritten = write_data(cli->trans.sock.fd, pdata, data_len); - if (nwritten == -1) { - ret = map_nt_error_from_unix(errno); - DEBUG(0, ("rpc_api_pipe: write_data returned %s\n", - strerror(errno))); - goto err; - } - rparam = NULL; - prdata = SMB_MALLOC_ARRAY(char, 1); - if (prdata == NULL) { - return NT_STATUS_NO_MEMORY; - } - nread = sys_read(cli->trans.sock.fd, prdata, 1); - if (nread == 0) { - SAFE_FREE(prdata); - } - if (nread == -1) { - ret = NT_STATUS_END_OF_FILE; - goto err; - } - rdata_len = nread; - break; - } - default: - DEBUG(0, ("unknown transport type %d\n", - cli->transport_type)); - return NT_STATUS_INTERNAL_ERROR; + DEBUG(0, ("rpc_api_pipe: Remote machine %s pipe %s fnum 0x%x " + "returned critical error. Error was %s\n", + cli->cli->desthost, + cli->pipe_name, + (unsigned int)cli->fnum, + cli_errstr(cli->cli))); + ret = cli_get_nt_error(cli->cli); + SAFE_FREE(rparam); + SAFE_FREE(prdata); + goto err; } /* Throw away returned params - we know we won't use them. */ @@ -957,8 +798,11 @@ static NTSTATUS rpc_api_pipe(struct rpc_pipe_client *cli, SAFE_FREE(rparam); if (prdata == NULL) { - DEBUG(3,("rpc_api_pipe: %s failed to return data.\n", - rpccli_pipe_txt(debug_ctx(), cli))); + DEBUG(3,("rpc_api_pipe: Remote machine %s pipe %s " + "fnum 0x%x failed to return data.\n", + cli->cli->desthost, + cli->pipe_name, + (unsigned int)cli->fnum)); /* Yes - some calls can truely return no data... */ prs_mem_free(¤t_pdu); return NT_STATUS_OK; @@ -1004,9 +848,11 @@ static NTSTATUS rpc_api_pipe(struct rpc_pipe_client *cli, if ((rhdr.flags & RPC_FLG_FIRST)) { if (rhdr.pack_type[0] == 0) { /* Set the data type correctly for big-endian data on the first packet. */ - DEBUG(10,("rpc_api_pipe: On %s " + DEBUG(10,("rpc_api_pipe: On machine %s pipe %s fnum 0x%x " "PDU data format is big-endian.\n", - rpccli_pipe_txt(debug_ctx(), cli))); + cli->cli->desthost, + cli->pipe_name, + (unsigned int)cli->fnum)); prs_set_endian_data(rbuf, RPC_BIG_ENDIAN); } else { @@ -1040,8 +886,10 @@ static NTSTATUS rpc_api_pipe(struct rpc_pipe_client *cli, } } - DEBUG(10,("rpc_api_pipe: %s returned %u bytes.\n", - rpccli_pipe_txt(debug_ctx(), cli), + DEBUG(10,("rpc_api_pipe: Remote machine %s pipe %s fnum 0x%x returned %u bytes.\n", + cli->cli->desthost, + cli->pipe_name, + (unsigned int)cli->fnum, (unsigned int)prs_data_size(rbuf) )); prs_mem_free(¤t_pdu); @@ -1065,7 +913,7 @@ static NTSTATUS create_krb5_auth_bind_req( struct rpc_pipe_client *cli, { #ifdef HAVE_KRB5 int ret; - struct kerberos_auth_struct *a = cli->auth->a_u.kerberos_auth; + struct kerberos_auth_struct *a = cli->auth.a_u.kerberos_auth; DATA_BLOB tkt = data_blob_null; DATA_BLOB tkt_wrapped = data_blob_null; @@ -1131,7 +979,7 @@ static NTSTATUS create_spnego_ntlmssp_auth_rpc_bind_req( struct rpc_pipe_client init_rpc_hdr_auth(pauth_out, RPC_SPNEGO_AUTH_TYPE, (int)auth_level, 0, 1); DEBUG(5, ("create_spnego_ntlmssp_auth_rpc_bind_req: Processing NTLMSSP Negotiate\n")); - nt_status = ntlmssp_update(cli->auth->a_u.ntlmssp_state, + nt_status = ntlmssp_update(cli->auth.a_u.ntlmssp_state, null_blob, &request); @@ -1177,7 +1025,7 @@ static NTSTATUS create_ntlmssp_auth_rpc_bind_req( struct rpc_pipe_client *cli, init_rpc_hdr_auth(pauth_out, RPC_NTLMSSP_AUTH_TYPE, (int)auth_level, 0, 1); DEBUG(5, ("create_ntlmssp_auth_rpc_bind_req: Processing NTLMSSP Negotiate\n")); - nt_status = ntlmssp_update(cli->auth->a_u.ntlmssp_state, + nt_status = ntlmssp_update(cli->auth.a_u.ntlmssp_state, null_blob, &request); @@ -1217,15 +1065,11 @@ static NTSTATUS create_schannel_auth_rpc_bind_req( struct rpc_pipe_client *cli, /* Use lp_workgroup() if domain not specified */ - if (!cli->auth->domain || !cli->auth->domain[0]) { - cli->auth->domain = talloc_strdup(cli, lp_workgroup()); - if (cli->auth->domain == NULL) { - return NT_STATUS_NO_MEMORY; - } + if (!cli->domain || !cli->domain[0]) { + cli->domain = lp_workgroup(); } - init_rpc_auth_schannel_neg(&schannel_neg, cli->auth->domain, - global_myname()); + init_rpc_auth_schannel_neg(&schannel_neg, cli->domain, global_myname()); /* * Now marshall the data into the auth parse_struct. @@ -1248,8 +1092,8 @@ static NTSTATUS create_schannel_auth_rpc_bind_req( struct rpc_pipe_client *cli, static NTSTATUS create_bind_or_alt_ctx_internal(enum RPC_PKT_TYPE pkt_type, prs_struct *rpc_out, uint32 rpc_call_id, - const RPC_IFACE *abstract, - const RPC_IFACE *transfer, + RPC_IFACE *abstract, + RPC_IFACE *transfer, RPC_HDR_AUTH *phdr_auth, prs_struct *pauth_info) { @@ -1330,8 +1174,7 @@ static NTSTATUS create_bind_or_alt_ctx_internal(enum RPC_PKT_TYPE pkt_type, static NTSTATUS create_rpc_bind_req(struct rpc_pipe_client *cli, prs_struct *rpc_out, uint32 rpc_call_id, - const RPC_IFACE *abstract, - const RPC_IFACE *transfer, + RPC_IFACE *abstract, RPC_IFACE *transfer, enum pipe_auth_type auth_type, enum pipe_auth_level auth_level) { @@ -1410,15 +1253,14 @@ static NTSTATUS add_ntlmssp_auth_footer(struct rpc_pipe_client *cli, DATA_BLOB auth_blob = data_blob_null; uint16 data_and_pad_len = prs_offset(outgoing_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN; - if (!cli->auth->a_u.ntlmssp_state) { + if (!cli->auth.a_u.ntlmssp_state) { return NT_STATUS_INVALID_PARAMETER; } /* Init and marshall the auth header. */ init_rpc_hdr_auth(&auth_info, - map_pipe_auth_type_to_rpc_auth_type( - cli->auth->auth_type), - cli->auth->auth_level, + map_pipe_auth_type_to_rpc_auth_type(cli->auth.auth_type), + cli->auth.auth_level, ss_padding_len, 1 /* context id. */); @@ -1428,10 +1270,10 @@ static NTSTATUS add_ntlmssp_auth_footer(struct rpc_pipe_client *cli, return NT_STATUS_NO_MEMORY; } - switch (cli->auth->auth_level) { + switch (cli->auth.auth_level) { case PIPE_AUTH_LEVEL_PRIVACY: /* Data portion is encrypted. */ - status = ntlmssp_seal_packet(cli->auth->a_u.ntlmssp_state, + status = ntlmssp_seal_packet(cli->auth.a_u.ntlmssp_state, (unsigned char *)prs_data_p(outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN, data_and_pad_len, (unsigned char *)prs_data_p(outgoing_pdu), @@ -1445,7 +1287,7 @@ static NTSTATUS add_ntlmssp_auth_footer(struct rpc_pipe_client *cli, case PIPE_AUTH_LEVEL_INTEGRITY: /* Data is signed. */ - status = ntlmssp_sign_packet(cli->auth->a_u.ntlmssp_state, + status = ntlmssp_sign_packet(cli->auth.a_u.ntlmssp_state, (unsigned char *)prs_data_p(outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN, data_and_pad_len, (unsigned char *)prs_data_p(outgoing_pdu), @@ -1465,14 +1307,14 @@ static NTSTATUS add_ntlmssp_auth_footer(struct rpc_pipe_client *cli, } /* Finally marshall the blob. */ - + if (!prs_copy_data_in(outgoing_pdu, (const char *)auth_blob.data, NTLMSSP_SIG_SIZE)) { DEBUG(0,("add_ntlmssp_auth_footer: failed to add %u bytes auth blob.\n", (unsigned int)NTLMSSP_SIG_SIZE)); data_blob_free(&auth_blob); return NT_STATUS_NO_MEMORY; } - + data_blob_free(&auth_blob); return NT_STATUS_OK; } @@ -1488,7 +1330,7 @@ static NTSTATUS add_schannel_auth_footer(struct rpc_pipe_client *cli, { RPC_HDR_AUTH auth_info; RPC_AUTH_SCHANNEL_CHK verf; - struct schannel_auth_struct *sas = cli->auth->a_u.schannel_auth; + struct schannel_auth_struct *sas = cli->auth.a_u.schannel_auth; char *data_p = prs_data_p(outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN; size_t data_and_pad_len = prs_offset(outgoing_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN; @@ -1498,8 +1340,8 @@ static NTSTATUS add_schannel_auth_footer(struct rpc_pipe_client *cli, /* Init and marshall the auth header. */ init_rpc_hdr_auth(&auth_info, - map_pipe_auth_type_to_rpc_auth_type(cli->auth->auth_type), - cli->auth->auth_level, + map_pipe_auth_type_to_rpc_auth_type(cli->auth.auth_type), + cli->auth.auth_level, ss_padding_len, 1 /* context id. */); @@ -1508,14 +1350,14 @@ static NTSTATUS add_schannel_auth_footer(struct rpc_pipe_client *cli, return NT_STATUS_NO_MEMORY; } - switch (cli->auth->auth_level) { + switch (cli->auth.auth_level) { case PIPE_AUTH_LEVEL_PRIVACY: case PIPE_AUTH_LEVEL_INTEGRITY: DEBUG(10,("add_schannel_auth_footer: SCHANNEL seq_num=%d\n", sas->seq_num)); schannel_encode(sas, - cli->auth->auth_level, + cli->auth.auth_level, SENDER_IS_INITIATOR, &verf, data_p, @@ -1537,7 +1379,7 @@ static NTSTATUS add_schannel_auth_footer(struct rpc_pipe_client *cli, &verf, outgoing_pdu, 0); - + return NT_STATUS_OK; } @@ -1554,7 +1396,7 @@ static uint32 calculate_data_len_tosend(struct rpc_pipe_client *cli, { uint32 data_space, data_len; - switch (cli->auth->auth_level) { + switch (cli->auth.auth_level) { case PIPE_AUTH_LEVEL_NONE: case PIPE_AUTH_LEVEL_CONNECT: data_space = cli->max_xmit_frag - RPC_HEADER_LEN - RPC_HDR_REQ_LEN; @@ -1567,7 +1409,7 @@ static uint32 calculate_data_len_tosend(struct rpc_pipe_client *cli, case PIPE_AUTH_LEVEL_INTEGRITY: case PIPE_AUTH_LEVEL_PRIVACY: /* Treat the same for all authenticated rpc requests. */ - switch(cli->auth->auth_type) { + switch(cli->auth.auth_type) { case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: case PIPE_AUTH_TYPE_NTLMSSP: *p_auth_len = NTLMSSP_SIG_SIZE; @@ -1681,7 +1523,7 @@ NTSTATUS rpc_api_pipe_req(struct rpc_pipe_client *cli, /* Generate any auth sign/seal and add the auth footer. */ if (auth_len) { - switch (cli->auth->auth_type) { + switch (cli->auth.auth_type) { case PIPE_AUTH_TYPE_NONE: break; case PIPE_AUTH_TYPE_NTLMSSP: @@ -1711,13 +1553,12 @@ NTSTATUS rpc_api_pipe_req(struct rpc_pipe_client *cli, ret = rpc_api_pipe(cli, &outgoing_pdu, out_data, RPC_RESPONSE); prs_mem_free(&outgoing_pdu); - if ((DEBUGLEVEL >= 50) - && (cli->transport_type == NCACN_NP)) { + if (DEBUGLEVEL >= 50) { char *dump_name = NULL; /* Also capture received data */ if (asprintf(&dump_name, "%s/reply_%s_%d", - get_dyn_LOGFILEBASE(), - cli->trans.np.pipe_name, op_num) > 0) { + get_dyn_LOGFILEBASE(), cli->pipe_name, + op_num) > 0) { prs_dump(dump_name, op_num, out_data); SAFE_FREE(dump_name); } @@ -1726,40 +1567,14 @@ NTSTATUS rpc_api_pipe_req(struct rpc_pipe_client *cli, return ret; } else { /* More packets to come - write and continue. */ - ssize_t num_written; - - switch (cli->transport_type) { - case NCACN_NP: - num_written = cli_write(cli->trans.np.cli, - cli->trans.np.fnum, - 8, /* 8 means message mode. */ + ssize_t num_written = cli_write(cli->cli, cli->fnum, 8, /* 8 means message mode. */ prs_data_p(&outgoing_pdu), (off_t)0, (size_t)hdr.frag_len); - if (num_written != hdr.frag_len) { - prs_mem_free(&outgoing_pdu); - return cli_get_nt_error( - cli->trans.np.cli); - } - break; - case NCACN_IP_TCP: - case NCACN_UNIX_STREAM: - num_written = write_data( - cli->trans.sock.fd, - prs_data_p(&outgoing_pdu), - (size_t)hdr.frag_len); - if (num_written != hdr.frag_len) { - NTSTATUS status; - status = map_nt_error_from_unix(errno); - prs_mem_free(&outgoing_pdu); - return status; - } - break; - default: - DEBUG(0, ("unknown transport type %d\n", - cli->transport_type)); - return NT_STATUS_INTERNAL_ERROR; + if (num_written != hdr.frag_len) { + prs_mem_free(&outgoing_pdu); + return cli_get_nt_error(cli->cli); } } @@ -1824,14 +1639,58 @@ static bool rpc_pipe_set_hnd_state(struct rpc_pipe_client *cli, Check the rpc bind acknowledge response. ****************************************************************************/ -static bool check_bind_response(RPC_HDR_BA *hdr_ba, const RPC_IFACE *transfer) +static bool valid_pipe_name(const int pipe_idx, RPC_IFACE *abstract, RPC_IFACE *transfer) +{ + if ( pipe_idx >= PI_MAX_PIPES ) { + DEBUG(0,("valid_pipe_name: Programmer error! Invalid pipe index [%d]\n", + pipe_idx)); + return False; + } + + DEBUG(5,("Bind Abstract Syntax: ")); + dump_data(5, (uint8 *)&pipe_names[pipe_idx].abstr_syntax, + sizeof(pipe_names[pipe_idx].abstr_syntax)); + DEBUG(5,("Bind Transfer Syntax: ")); + dump_data(5, (uint8 *)&pipe_names[pipe_idx].trans_syntax, + sizeof(pipe_names[pipe_idx].trans_syntax)); + + /* copy the required syntaxes out so we can do the right bind */ + + *transfer = pipe_names[pipe_idx].trans_syntax; + *abstract = pipe_names[pipe_idx].abstr_syntax; + + return True; +} + +/**************************************************************************** + Check the rpc bind acknowledge response. +****************************************************************************/ + +static bool check_bind_response(RPC_HDR_BA *hdr_ba, const int pipe_idx, RPC_IFACE *transfer) { if ( hdr_ba->addr.len == 0) { DEBUG(4,("Ignoring length check -- ASU bug (server didn't fill in the pipe name correctly)")); } +# if 0 /* JERRY -- apparently ASU forgets to fill in the server pipe name sometimes */ + if ( !strequal(hdr_ba->addr.str, pipe_names[pipe_idx].client_pipe) && + !strequal(hdr_ba->addr.str, pipe_names[pipe_idx].server_pipe) ) + { + DEBUG(4,("bind_rpc_pipe: pipe_name %s != expected pipe %s. oh well!\n", + pipe_names[i].server_pipe ,hdr_ba->addr.str)); + return False; + } + + DEBUG(5,("bind_rpc_pipe: server pipe_name found: %s\n", pipe_names[i].server_pipe )); + + if (pipe_names[pipe_idx].server_pipe == NULL) { + DEBUG(2,("bind_rpc_pipe: pipe name %s unsupported\n", hdr_ba->addr.str)); + return False; + } +#endif /* JERRY */ + /* check the transfer syntax */ - if ((hdr_ba->transfer.if_version != transfer->if_version) || + if ((hdr_ba->transfer.version != transfer->version) || (memcmp(&hdr_ba->transfer.uuid, &transfer->uuid, sizeof(transfer->uuid)) !=0)) { DEBUG(2,("bind_rpc_pipe: transfer syntax differs\n")); return False; @@ -1868,7 +1727,7 @@ static NTSTATUS create_rpc_bind_auth3(struct rpc_pipe_client *cli, init_rpc_hdr(&hdr, RPC_AUTH3, RPC_FLG_FIRST|RPC_FLG_LAST, rpc_call_id, RPC_HEADER_LEN + 4 /* pad */ + RPC_HDR_AUTH_LEN + pauth_blob->length, pauth_blob->length ); - + /* Marshall it. */ if(!smb_io_rpc_hdr("hdr", &hdr, rpc_out, 0)) { DEBUG(0,("create_rpc_bind_auth3: failed to marshall RPC_HDR.\n")); @@ -1943,11 +1802,11 @@ static NTSTATUS rpc_finish_auth3_bind(struct rpc_pipe_client *cli, server_response = data_blob(NULL, phdr->auth_len); prs_copy_data_out((char *)server_response.data, rbuf, phdr->auth_len); - - nt_status = ntlmssp_update(cli->auth->a_u.ntlmssp_state, + + nt_status = ntlmssp_update(cli->auth.a_u.ntlmssp_state, server_response, &client_reply); - + if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0,("rpc_finish_auth3_bind: NTLMSSP update using server blob failed.\n")); data_blob_free(&server_response); @@ -1967,41 +1826,23 @@ static NTSTATUS rpc_finish_auth3_bind(struct rpc_pipe_client *cli, return nt_status; } - switch (cli->transport_type) { - case NCACN_NP: - /* 8 here is named pipe message mode. */ - ret = cli_write(cli->trans.np.cli, cli->trans.np.fnum, - 0x8, prs_data_p(&rpc_out), 0, + /* 8 here is named pipe message mode. */ + ret = cli_write(cli->cli, cli->fnum, 0x8, prs_data_p(&rpc_out), 0, (size_t)prs_offset(&rpc_out)); - break; - - if (ret != (ssize_t)prs_offset(&rpc_out)) { - nt_status = cli_get_nt_error(cli->trans.np.cli); - } - case NCACN_IP_TCP: - case NCACN_UNIX_STREAM: - ret = write_data(cli->trans.sock.fd, prs_data_p(&rpc_out), - (size_t)prs_offset(&rpc_out)); - if (ret != (ssize_t)prs_offset(&rpc_out)) { - nt_status = map_nt_error_from_unix(errno); - } - break; - default: - DEBUG(0, ("unknown transport type %d\n", cli->transport_type)); - return NT_STATUS_INTERNAL_ERROR; - } if (ret != (ssize_t)prs_offset(&rpc_out)) { - DEBUG(0,("rpc_send_auth_auth3: write failed. Return was %s\n", - nt_errstr(nt_status))); + DEBUG(0,("rpc_send_auth_auth3: cli_write failed. Return was %d\n", (int)ret)); prs_mem_free(&rpc_out); data_blob_free(&client_reply); data_blob_free(&server_response); - return nt_status; + return cli_get_nt_error(cli->cli); } - DEBUG(5,("rpc_send_auth_auth3: %s sent auth3 response ok.\n", - rpccli_pipe_txt(debug_ctx(), cli))); + DEBUG(5,("rpc_send_auth_auth3: Remote machine %s pipe %s " + "fnum 0x%x sent auth3 response ok.\n", + cli->cli->desthost, + cli->pipe_name, + (unsigned int)cli->fnum)); prs_mem_free(&rpc_out); data_blob_free(&client_reply); @@ -2015,8 +1856,8 @@ static NTSTATUS rpc_finish_auth3_bind(struct rpc_pipe_client *cli, ********************************************************************/ static NTSTATUS create_rpc_alter_context(uint32 rpc_call_id, - const RPC_IFACE *abstract, - const RPC_IFACE *transfer, + RPC_IFACE *abstract, + RPC_IFACE *transfer, enum pipe_auth_level auth_level, const DATA_BLOB *pauth_blob, /* spnego auth blob already created. */ prs_struct *rpc_out) @@ -2059,8 +1900,8 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind(struct rpc_pipe_client *cli, RPC_HDR *phdr, prs_struct *rbuf, uint32 rpc_call_id, - const RPC_IFACE *abstract, - const RPC_IFACE *transfer, + RPC_IFACE *abstract, + RPC_IFACE *transfer, enum pipe_auth_type auth_type, enum pipe_auth_level auth_level) { @@ -2087,7 +1928,7 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind(struct rpc_pipe_client *cli, server_spnego_response = data_blob(NULL, phdr->auth_len); prs_copy_data_out((char *)server_spnego_response.data, rbuf, phdr->auth_len); - + /* The server might give us back two challenges - tmp_blob is for the second. */ if (!spnego_parse_challenge(server_spnego_response, &server_ntlm_response, &tmp_blob)) { data_blob_free(&server_spnego_response); @@ -2100,10 +1941,10 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind(struct rpc_pipe_client *cli, data_blob_free(&server_spnego_response); data_blob_free(&tmp_blob); - nt_status = ntlmssp_update(cli->auth->a_u.ntlmssp_state, + nt_status = ntlmssp_update(cli->auth.a_u.ntlmssp_state, server_ntlm_response, &client_reply); - + /* Finished with the server_ntlm response */ data_blob_free(&server_ntlm_response); @@ -2138,7 +1979,7 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind(struct rpc_pipe_client *cli, /* Initialize the returning data struct. */ prs_mem_free(rbuf); - prs_init_empty(rbuf, talloc_tos(), UNMARSHALL); + prs_init_empty(rbuf, cli->mem_ctx, UNMARSHALL); nt_status = rpc_api_pipe(cli, &rpc_out, rbuf, RPC_ALTCONTRESP); if (!NT_STATUS_IS_OK(nt_status)) { @@ -2176,7 +2017,10 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind(struct rpc_pipe_client *cli, data_blob_free(&tmp_blob); DEBUG(5,("rpc_finish_spnego_ntlmssp_bind: alter context request to " - "%s.\n", rpccli_pipe_txt(debug_ctx(), cli))); + "remote machine %s pipe %s fnum 0x%x.\n", + cli->cli->desthost, + cli->pipe_name, + (unsigned int)cli->fnum)); return NT_STATUS_OK; } @@ -2185,33 +2029,38 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind(struct rpc_pipe_client *cli, Do an rpc bind. ****************************************************************************/ -NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli, - struct cli_pipe_auth_data *auth) +static NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli, + enum pipe_auth_type auth_type, + enum pipe_auth_level auth_level) { RPC_HDR hdr; RPC_HDR_BA hdr_ba; + RPC_IFACE abstract; + RPC_IFACE transfer; prs_struct rpc_out; prs_struct rbuf; uint32 rpc_call_id; NTSTATUS status; - DEBUG(5,("Bind RPC Pipe: %s auth_type %u, auth_level %u\n", - rpccli_pipe_txt(debug_ctx(), cli), - (unsigned int)auth->auth_type, - (unsigned int)auth->auth_level )); + DEBUG(5,("Bind RPC Pipe[%x]: %s auth_type %u, auth_level %u\n", + (unsigned int)cli->fnum, + cli->pipe_name, + (unsigned int)auth_type, + (unsigned int)auth_level )); - cli->auth = talloc_move(cli, &auth); + if (!valid_pipe_name(cli->pipe_idx, &abstract, &transfer)) { + return NT_STATUS_INVALID_PARAMETER; + } - prs_init_empty(&rpc_out, talloc_tos(), MARSHALL); + prs_init_empty(&rpc_out, cli->mem_ctx, MARSHALL); rpc_call_id = get_rpc_call_id(); /* Marshall the outgoing data. */ status = create_rpc_bind_req(cli, &rpc_out, rpc_call_id, - &cli->abstract_syntax, - &cli->transfer_syntax, - cli->auth->auth_type, - cli->auth->auth_level); + &abstract, &transfer, + auth_type, + auth_level); if (!NT_STATUS_IS_OK(status)) { prs_mem_free(&rpc_out); @@ -2219,7 +2068,7 @@ NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli, } /* Initialize the incoming data struct. */ - prs_init_empty(&rbuf, talloc_tos(), UNMARSHALL); + prs_init_empty(&rbuf, cli->mem_ctx, UNMARSHALL); /* send data on \PIPE\. receive a response */ status = rpc_api_pipe(cli, &rpc_out, &rbuf, RPC_BINDACK); @@ -2230,8 +2079,11 @@ NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli, prs_mem_free(&rpc_out); - DEBUG(3,("rpc_pipe_bind: %s bind request returned ok.\n", - rpccli_pipe_txt(debug_ctx(), cli))); + DEBUG(3,("rpc_pipe_bind: Remote machine %s pipe %s " + "fnum 0x%x bind request returned ok.\n", + cli->cli->desthost, + cli->pipe_name, + (unsigned int)cli->fnum)); /* Unmarshall the RPC header */ if(!smb_io_rpc_hdr("hdr" , &hdr, &rbuf, 0)) { @@ -2246,7 +2098,7 @@ NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli, return NT_STATUS_BUFFER_TOO_SMALL; } - if(!check_bind_response(&hdr_ba, &cli->transfer_syntax)) { + if(!check_bind_response(&hdr_ba, cli->pipe_idx, &transfer)) { DEBUG(2,("rpc_pipe_bind: check_bind_response failed.\n")); prs_mem_free(&rbuf); return NT_STATUS_BUFFER_TOO_SMALL; @@ -2256,7 +2108,7 @@ NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli, cli->max_recv_frag = hdr_ba.bba.max_rsize; /* For authenticated binds we may need to do 3 or 4 leg binds. */ - switch(cli->auth->auth_type) { + switch(auth_type) { case PIPE_AUTH_TYPE_NONE: case PIPE_AUTH_TYPE_SCHANNEL: @@ -2265,10 +2117,8 @@ NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli, case PIPE_AUTH_TYPE_NTLMSSP: /* Need to send AUTH3 packet - no reply. */ - status = rpc_finish_auth3_bind( - cli, &hdr, &rbuf, rpc_call_id, - cli->auth->auth_type, - cli->auth->auth_level); + status = rpc_finish_auth3_bind(cli, &hdr, &rbuf, rpc_call_id, + auth_type, auth_level); if (!NT_STATUS_IS_OK(status)) { prs_mem_free(&rbuf); return status; @@ -2277,10 +2127,9 @@ NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli, case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: /* Need to send alter context request and reply. */ - status = rpc_finish_spnego_ntlmssp_bind( - cli, &hdr, &rbuf, rpc_call_id, - &cli->abstract_syntax, &cli->transfer_syntax, - cli->auth->auth_type, cli->auth->auth_level); + status = rpc_finish_spnego_ntlmssp_bind(cli, &hdr, &rbuf, rpc_call_id, + &abstract, &transfer, + auth_type, auth_level); if (!NT_STATUS_IS_OK(status)) { prs_mem_free(&rbuf); return status; @@ -2291,24 +2140,23 @@ NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli, /* */ default: - DEBUG(0,("cli_finish_bind_auth: unknown auth type " - "%u\n", (unsigned int)cli->auth->auth_type)); + DEBUG(0,("cli_finish_bind_auth: unknown auth type %u\n", + (unsigned int)auth_type )); prs_mem_free(&rbuf); return NT_STATUS_INVALID_INFO_CLASS; } /* For NTLMSSP ensure the server gave us the auth_level we wanted. */ - if (cli->auth->auth_type == PIPE_AUTH_TYPE_NTLMSSP - || cli->auth->auth_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) { - if (cli->auth->auth_level == PIPE_AUTH_LEVEL_INTEGRITY) { - if (!(cli->auth->a_u.ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN)) { + if (auth_type == PIPE_AUTH_TYPE_NTLMSSP || auth_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) { + if (auth_level == PIPE_AUTH_LEVEL_INTEGRITY) { + if (!(cli->auth.a_u.ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN)) { DEBUG(0,("cli_finish_bind_auth: requested NTLMSSSP signing and server refused.\n")); prs_mem_free(&rbuf); return NT_STATUS_INVALID_PARAMETER; } } - if (cli->auth->auth_level == PIPE_AUTH_LEVEL_INTEGRITY) { - if (!(cli->auth->a_u.ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL)) { + if (auth_level == PIPE_AUTH_LEVEL_INTEGRITY) { + if (!(cli->auth.a_u.ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL)) { DEBUG(0,("cli_finish_bind_auth: requested NTLMSSSP sealing and server refused.\n")); prs_mem_free(&rbuf); return NT_STATUS_INVALID_PARAMETER; @@ -2316,543 +2164,15 @@ NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli, } } - prs_mem_free(&rbuf); - return NT_STATUS_OK; -} - -unsigned int rpccli_set_timeout(struct rpc_pipe_client *cli, - unsigned int timeout) -{ - return cli_set_timeout(cli->trans.np.cli, timeout); -} - -bool rpccli_get_pwd_hash(struct rpc_pipe_client *cli, uint8_t nt_hash[16]) -{ - if ((cli->auth->auth_type == PIPE_AUTH_TYPE_NTLMSSP) - || (cli->auth->auth_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP)) { - memcpy(nt_hash, cli->auth->a_u.ntlmssp_state->nt_hash, 16); - return true; - } - - if (cli->transport_type == NCACN_NP) { - E_md4hash(cli->trans.np.cli->pwd.password, nt_hash); - return true; - } - - return false; -} - -struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p) -{ - if (p->transport_type == NCACN_NP) { - return p->trans.np.cli; - } - return NULL; -} - -static int rpc_pipe_destructor(struct rpc_pipe_client *p) -{ - if (p->transport_type == NCACN_NP) { - bool ret; - ret = cli_close(p->trans.np.cli, p->trans.np.fnum); - if (!ret) { - DEBUG(1, ("rpc_pipe_destructor: cli_close failed on " - "pipe %s. Error was %s\n", - rpccli_pipe_txt(debug_ctx(), p), - cli_errstr(p->trans.np.cli))); - } - - DEBUG(10, ("rpc_pipe_destructor: closed %s\n", - rpccli_pipe_txt(debug_ctx(), p))); - - DLIST_REMOVE(p->trans.np.cli->pipe_list, p); - return ret ? -1 : 0; - } - - return -1; -} - -NTSTATUS rpccli_anon_bind_data(TALLOC_CTX *mem_ctx, - struct cli_pipe_auth_data **presult) -{ - struct cli_pipe_auth_data *result; - - result = talloc(mem_ctx, struct cli_pipe_auth_data); - if (result == NULL) { - return NT_STATUS_NO_MEMORY; - } - - result->auth_type = PIPE_AUTH_TYPE_NONE; - result->auth_level = PIPE_AUTH_LEVEL_NONE; - - 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; -} - -static int cli_auth_ntlmssp_data_destructor(struct cli_pipe_auth_data *auth) -{ - ntlmssp_end(&auth->a_u.ntlmssp_state); - return 0; -} - -NTSTATUS rpccli_ntlmssp_bind_data(TALLOC_CTX *mem_ctx, - enum pipe_auth_type auth_type, - enum pipe_auth_level auth_level, - const char *domain, - const char *username, - const char *password, - struct cli_pipe_auth_data **presult) -{ - struct cli_pipe_auth_data *result; - NTSTATUS status; - - result = talloc(mem_ctx, struct cli_pipe_auth_data); - 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; - } - - status = ntlmssp_client_start(&result->a_u.ntlmssp_state); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } + /* Pipe is bound - set up auth_type and auth_level data. */ - talloc_set_destructor(result, cli_auth_ntlmssp_data_destructor); - - status = ntlmssp_set_username(result->a_u.ntlmssp_state, username); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - - status = ntlmssp_set_domain(result->a_u.ntlmssp_state, domain); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - - status = ntlmssp_set_password(result->a_u.ntlmssp_state, password); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - - /* - * Turn off sign+seal to allow selected auth level to turn it back on. - */ - result->a_u.ntlmssp_state->neg_flags &= - ~(NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL); - - if (auth_level == PIPE_AUTH_LEVEL_INTEGRITY) { - result->a_u.ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; - } else if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) { - result->a_u.ntlmssp_state->neg_flags - |= NTLMSSP_NEGOTIATE_SEAL | NTLMSSP_NEGOTIATE_SIGN; - } - - *presult = result; - return NT_STATUS_OK; - - fail: - TALLOC_FREE(result); - return status; -} - -NTSTATUS rpccli_schannel_bind_data(TALLOC_CTX *mem_ctx, const char *domain, - enum pipe_auth_level auth_level, - const uint8_t sess_key[16], - struct cli_pipe_auth_data **presult) -{ - struct cli_pipe_auth_data *result; - - result = talloc(mem_ctx, struct cli_pipe_auth_data); - if (result == NULL) { - return NT_STATUS_NO_MEMORY; - } - - result->auth_type = PIPE_AUTH_TYPE_SCHANNEL; - result->auth_level = auth_level; - - result->user_name = talloc_strdup(result, ""); - result->domain = talloc_strdup(result, domain); - if ((result->user_name == NULL) || (result->domain == NULL)) { - goto fail; - } - - result->a_u.schannel_auth = talloc(result, - struct schannel_auth_struct); - if (result->a_u.schannel_auth == NULL) { - goto fail; - } - - memcpy(result->a_u.schannel_auth->sess_key, sess_key, - sizeof(result->a_u.schannel_auth->sess_key)); - result->a_u.schannel_auth->seq_num = 0; - - *presult = result; - return NT_STATUS_OK; - - fail: - TALLOC_FREE(result); - return NT_STATUS_NO_MEMORY; -} - -#ifdef HAVE_KRB5 -static int cli_auth_kerberos_data_destructor(struct kerberos_auth_struct *auth) -{ - data_blob_free(&auth->session_key); - return 0; -} -#endif - -NTSTATUS rpccli_kerberos_bind_data(TALLOC_CTX *mem_ctx, - enum pipe_auth_level auth_level, - const char *service_princ, - const char *username, - const char *password, - struct cli_pipe_auth_data **presult) -{ -#ifdef HAVE_KRB5 - struct cli_pipe_auth_data *result; - - if ((username != NULL) && (password != NULL)) { - int ret = kerberos_kinit_password(username, password, 0, NULL); - if (ret != 0) { - return NT_STATUS_ACCESS_DENIED; - } - } - - result = talloc(mem_ctx, struct cli_pipe_auth_data); - if (result == NULL) { - return NT_STATUS_NO_MEMORY; - } - - result->auth_type = PIPE_AUTH_TYPE_KRB5; - result->auth_level = auth_level; - - /* - * Username / domain need fixing! - */ - result->user_name = talloc_strdup(result, ""); - result->domain = talloc_strdup(result, ""); - if ((result->user_name == NULL) || (result->domain == NULL)) { - goto fail; - } - - result->a_u.kerberos_auth = TALLOC_ZERO_P( - result, struct kerberos_auth_struct); - if (result->a_u.kerberos_auth == NULL) { - goto fail; - } - talloc_set_destructor(result->a_u.kerberos_auth, - cli_auth_kerberos_data_destructor); - - result->a_u.kerberos_auth->service_principal = talloc_strdup( - result, service_princ); - if (result->a_u.kerberos_auth->service_principal == NULL) { - goto fail; - } - - *presult = result; - return NT_STATUS_OK; - - fail: - TALLOC_FREE(result); - return NT_STATUS_NO_MEMORY; -#else - return NT_STATUS_NOT_SUPPORTED; -#endif -} - -static int rpc_pipe_sock_destructor(struct rpc_pipe_client *p) -{ - close(p->trans.sock.fd); - return 0; -} - -/** - * Create an rpc pipe client struct, connecting to a tcp port. - */ -static NTSTATUS rpc_pipe_open_tcp_port(TALLOC_CTX *mem_ctx, const char *host, - uint16_t port, - const struct ndr_syntax_id *abstract_syntax, - struct rpc_pipe_client **presult) -{ - struct rpc_pipe_client *result; - struct sockaddr_storage addr; - NTSTATUS status; - - result = TALLOC_ZERO_P(mem_ctx, struct rpc_pipe_client); - if (result == NULL) { - return NT_STATUS_NO_MEMORY; - } - - result->transport_type = NCACN_IP_TCP; - - result->abstract_syntax = *abstract_syntax; - result->transfer_syntax = ndr_transfer_syntax; - - 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; - - if (!resolve_name(host, &addr, 0)) { - status = NT_STATUS_NOT_FOUND; - goto fail; - } - - result->trans.sock.fd = open_socket_out(SOCK_STREAM, &addr, port, 60); - if (result->trans.sock.fd == -1) { - status = map_nt_error_from_unix(errno); - goto fail; - } + cli->auth.auth_type = auth_type; + cli->auth.auth_level = auth_level; - talloc_set_destructor(result, rpc_pipe_sock_destructor); - - *presult = result; - return NT_STATUS_OK; - - fail: - TALLOC_FREE(result); - return status; -} - -/** - * 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. - */ -static NTSTATUS rpc_pipe_get_tcp_port(const char *host, - const struct ndr_syntax_id *abstract_syntax, - uint16_t *pport) -{ - NTSTATUS status; - struct rpc_pipe_client *epm_pipe = NULL; - struct cli_pipe_auth_data *auth = NULL; - struct dcerpc_binding *map_binding = NULL; - struct dcerpc_binding *res_binding = NULL; - 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(); - - if (pport == NULL) { - status = NT_STATUS_INVALID_PARAMETER; - goto done; - } - - /* open the connection to the endpoint mapper */ - status = rpc_pipe_open_tcp_port(tmp_ctx, host, 135, - &ndr_table_epmapper.syntax_id, - &epm_pipe); - - if (!NT_STATUS_IS_OK(status)) { - goto done; - } - - 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 */ - - map_binding = TALLOC_ZERO_P(tmp_ctx, struct dcerpc_binding); - if (map_binding == NULL) { - status = NT_STATUS_NO_MEMORY; - goto done; - } - - map_binding->transport = NCACN_IP_TCP; - map_binding->object = *abstract_syntax; - map_binding->host = host; /* needed? */ - map_binding->endpoint = "0"; /* correct? needed? */ - - map_tower = TALLOC_ZERO_P(tmp_ctx, struct epm_twr_t); - 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 */ - - res_towers = TALLOC_ARRAY(tmp_ctx, struct epm_twr_t, max_towers); - if (res_towers == NULL) { - status = NT_STATUS_NO_MEMORY; - goto done; - } - towers.twr = res_towers; - - entry_handle = TALLOC_ZERO_P(tmp_ctx, struct policy_handle); - if (entry_handle == NULL) { - status = NT_STATUS_NO_MEMORY; - goto done; - } - - /* ask the endpoint mapper for the port */ - - status = rpccli_epm_Map(epm_pipe, - tmp_ctx, - CONST_DISCARD(struct GUID *, - &(abstract_syntax->uuid)), - map_tower, - entry_handle, - max_towers, - &num_towers, - &towers); - - if (!NT_STATUS_IS_OK(status)) { - goto done; - } - - 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; - } - - /* are further checks here necessary? */ - if (res_binding->transport != NCACN_IP_TCP) { - status = NT_STATUS_UNSUCCESSFUL; - goto done; - } - - *pport = (uint16_t)atoi(res_binding->endpoint); - -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, - const struct ndr_syntax_id *abstract_syntax, - struct rpc_pipe_client **presult) -{ - NTSTATUS status; - uint16_t port = 0; - - *presult = NULL; - - status = rpc_pipe_get_tcp_port(host, abstract_syntax, &port); - if (!NT_STATUS_IS_OK(status)) { - goto done; - } - - status = rpc_pipe_open_tcp_port(mem_ctx, host, port, - abstract_syntax, presult); - -done: - return status; -} - -/******************************************************************** - 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, - const struct ndr_syntax_id *abstract_syntax, - struct rpc_pipe_client **presult) -{ - struct rpc_pipe_client *result; - struct sockaddr_un addr; - NTSTATUS status; - - result = talloc_zero(mem_ctx, struct rpc_pipe_client); - if (result == NULL) { - return NT_STATUS_NO_MEMORY; - } - - result->transport_type = NCACN_UNIX_STREAM; - - result->abstract_syntax = *abstract_syntax; - result->transfer_syntax = ndr_transfer_syntax; - - result->desthost = get_myname(result); - 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; - - result->trans.sock.fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (result->trans.sock.fd == -1) { - status = map_nt_error_from_unix(errno); - goto fail; - } - - talloc_set_destructor(result, rpc_pipe_sock_destructor); - - ZERO_STRUCT(addr); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)); - - if (sys_connect(result->trans.sock.fd, - (struct sockaddr *)&addr) == -1) { - DEBUG(0, ("connect(%s) failed: %s\n", socket_path, - strerror(errno))); - close(result->trans.sock.fd); - return map_nt_error_from_unix(errno); - } - - *presult = result; + prs_mem_free(&rbuf); return NT_STATUS_OK; - - fail: - TALLOC_FREE(result); - return status; } - /**************************************************************************** Open a named pipe over SMB to a remote server. * @@ -2866,204 +2186,199 @@ NTSTATUS rpc_pipe_open_ncalrpc(TALLOC_CTX *mem_ctx, const char *socket_path, * ****************************************************************************/ -static NTSTATUS rpc_pipe_open_np(struct cli_state *cli, - const struct ndr_syntax_id *abstract_syntax, - struct rpc_pipe_client **presult) +static struct rpc_pipe_client *cli_rpc_pipe_open(struct cli_state *cli, int pipe_idx, NTSTATUS *perr) { + TALLOC_CTX *mem_ctx; struct rpc_pipe_client *result; int fnum; + *perr = NT_STATUS_NO_MEMORY; + /* sanity check to protect against crashes */ if ( !cli ) { - return NT_STATUS_INVALID_HANDLE; + *perr = NT_STATUS_INVALID_HANDLE; + return NULL; } - result = TALLOC_ZERO_P(NULL, struct rpc_pipe_client); - if (result == NULL) { - return NT_STATUS_NO_MEMORY; - } + /* The pipe name index must fall within our array */ + SMB_ASSERT((pipe_idx >= 0) && (pipe_idx < PI_MAX_PIPES)); - result->transport_type = NCACN_NP; + mem_ctx = talloc_init("struct rpc_pipe_client"); + if (mem_ctx == NULL) { + return NULL; + } - result->trans.np.pipe_name = cli_get_pipe_name_from_iface( - result, cli, abstract_syntax); - if (result->trans.np.pipe_name == NULL) { - DEBUG(1, ("Could not find pipe for interface\n")); - TALLOC_FREE(result); - return NT_STATUS_INVALID_PARAMETER; + result = TALLOC_ZERO_P(mem_ctx, struct rpc_pipe_client); + if (result == NULL) { + return NULL; } - result->trans.np.cli = cli; - result->abstract_syntax = *abstract_syntax; - result->transfer_syntax = ndr_transfer_syntax; - result->desthost = talloc_strdup(result, cli->desthost); - result->srv_name_slash = talloc_asprintf_strupper_m( - result, "\\\\%s", result->desthost); + result->mem_ctx = mem_ctx; - if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) { - TALLOC_FREE(result); - return NT_STATUS_NO_MEMORY; - } + result->pipe_name = cli_get_pipe_name(pipe_idx); + + fnum = cli_nt_create(cli, result->pipe_name, DESIRED_ACCESS_PIPE); - fnum = cli_nt_create(cli, result->trans.np.pipe_name, - DESIRED_ACCESS_PIPE); if (fnum == -1) { - DEBUG(1,("rpc_pipe_open_np: cli_nt_create failed on pipe %s " + DEBUG(1,("cli_rpc_pipe_open: cli_nt_create failed on pipe %s " "to machine %s. Error was %s\n", - result->trans.np.pipe_name, cli->desthost, + result->pipe_name, cli->desthost, cli_errstr(cli))); - TALLOC_FREE(result); - return cli_get_nt_error(cli); + *perr = cli_get_nt_error(cli); + talloc_destroy(result->mem_ctx); + return NULL; + } + + result->fnum = fnum; + result->cli = cli; + result->pipe_idx = pipe_idx; + result->auth.auth_type = PIPE_AUTH_TYPE_NONE; + result->auth.auth_level = PIPE_AUTH_LEVEL_NONE; + + if (pipe_idx == PI_NETLOGON) { + /* Set up a netlogon credential chain for a netlogon pipe. */ + result->dc = TALLOC_ZERO_P(mem_ctx, struct dcinfo); + if (result->dc == NULL) { + talloc_destroy(result->mem_ctx); + return NULL; + } } - result->trans.np.fnum = fnum; - DLIST_ADD(cli->pipe_list, result); - talloc_set_destructor(result, rpc_pipe_destructor); - - *presult = result; - return NT_STATUS_OK; -} + *perr = NT_STATUS_OK; -/**************************************************************************** - Open a pipe to a remote server. - ****************************************************************************/ - -static NTSTATUS cli_rpc_pipe_open(struct cli_state *cli, - const struct ndr_syntax_id *interface, - struct rpc_pipe_client **presult) -{ - if (ndr_syntax_id_equal(interface, &ndr_table_drsuapi.syntax_id)) { - /* - * We should have a better way to figure out this drsuapi - * speciality... - */ - return rpc_pipe_open_tcp(NULL, cli->desthost, interface, - presult); - } - - return rpc_pipe_open_np(cli, interface, presult); + return result; } /**************************************************************************** Open a named pipe to an SMB server and bind anonymously. ****************************************************************************/ -NTSTATUS cli_rpc_pipe_open_noauth(struct cli_state *cli, - const struct ndr_syntax_id *interface, - struct rpc_pipe_client **presult) +struct rpc_pipe_client *cli_rpc_pipe_open_noauth(struct cli_state *cli, int pipe_idx, NTSTATUS *perr) { struct rpc_pipe_client *result; - struct cli_pipe_auth_data *auth; - NTSTATUS status; - - status = cli_rpc_pipe_open(cli, interface, &result); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - status = rpccli_anon_bind_data(result, &auth); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("rpccli_anon_bind_data returned %s\n", - nt_errstr(status))); - TALLOC_FREE(result); - return status; - } - - /* - * 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); - - if ((auth->user_name == NULL) || (auth->domain == NULL)) { - TALLOC_FREE(result); - return NT_STATUS_NO_MEMORY; + result = cli_rpc_pipe_open(cli, pipe_idx, perr); + if (result == NULL) { + return NULL; } - status = rpc_pipe_bind(result, auth); - if (!NT_STATUS_IS_OK(status)) { + *perr = rpc_pipe_bind(result, PIPE_AUTH_TYPE_NONE, PIPE_AUTH_LEVEL_NONE); + if (!NT_STATUS_IS_OK(*perr)) { int lvl = 0; - if (ndr_syntax_id_equal(interface, - &ndr_table_dssetup.syntax_id)) { + if (pipe_idx == PI_DSSETUP) { /* non AD domains just don't have this pipe, avoid * level 0 statement in that case - gd */ lvl = 3; } - DEBUG(lvl, ("cli_rpc_pipe_open_noauth: rpc_pipe_bind for pipe " - "%s failed with error %s\n", - cli_get_pipe_name_from_iface(debug_ctx(), cli, - interface), - nt_errstr(status) )); - TALLOC_FREE(result); - return status; + DEBUG(lvl, ("cli_rpc_pipe_open_noauth: rpc_pipe_bind for pipe %s failed with error %s\n", + cli_get_pipe_name(pipe_idx), nt_errstr(*perr) )); + cli_rpc_pipe_close(result); + return NULL; } - DEBUG(10,("cli_rpc_pipe_open_noauth: opened pipe %s to machine " - "%s and bound anonymously.\n", result->trans.np.pipe_name, - cli->desthost )); + DEBUG(10,("cli_rpc_pipe_open_noauth: opened pipe %s to machine %s and bound anonymously.\n", + result->pipe_name, cli->desthost )); - *presult = result; - return NT_STATUS_OK; + return result; +} + +/**************************************************************************** + Free function for NTLMSSP auth. + ****************************************************************************/ + +static void cli_ntlmssp_auth_free(struct cli_pipe_auth_data *auth) +{ + if (auth->a_u.ntlmssp_state) { + ntlmssp_end(&auth->a_u.ntlmssp_state); + auth->a_u.ntlmssp_state = NULL; + } } /**************************************************************************** Open a named pipe to an SMB server and bind using NTLMSSP or SPNEGO NTLMSSP ****************************************************************************/ -static NTSTATUS cli_rpc_pipe_open_ntlmssp_internal(struct cli_state *cli, - const struct ndr_syntax_id *interface, - enum pipe_auth_type auth_type, - enum pipe_auth_level auth_level, - const char *domain, - const char *username, - const char *password, - struct rpc_pipe_client **presult) +static struct rpc_pipe_client *cli_rpc_pipe_open_ntlmssp_internal(struct cli_state *cli, + int pipe_idx, + enum pipe_auth_type auth_type, + enum pipe_auth_level auth_level, + const char *domain, + const char *username, + const char *password, + NTSTATUS *perr) { struct rpc_pipe_client *result; - struct cli_pipe_auth_data *auth; - NTSTATUS status; + NTLMSSP_STATE *ntlmssp_state = NULL; - status = cli_rpc_pipe_open(cli, interface, &result); - if (!NT_STATUS_IS_OK(status)) { - return status; + result = cli_rpc_pipe_open(cli, pipe_idx, perr); + if (result == NULL) { + return NULL; } + + result->auth.cli_auth_data_free_func = cli_ntlmssp_auth_free; - status = rpccli_ntlmssp_bind_data( - result, auth_type, auth_level, domain, username, - cli->pwd.null_pwd ? NULL : password, &auth); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("rpccli_ntlmssp_bind_data returned %s\n", - nt_errstr(status))); + result->domain = domain; + result->user_name = username; + pwd_set_cleartext(&result->pwd, password); + + *perr = ntlmssp_client_start(&ntlmssp_state); + if (!NT_STATUS_IS_OK(*perr)) { goto err; } - status = rpc_pipe_bind(result, auth); - if (!NT_STATUS_IS_OK(status)) { + result->auth.a_u.ntlmssp_state = ntlmssp_state; + + *perr = ntlmssp_set_username(ntlmssp_state, cli->user_name); + if (!NT_STATUS_IS_OK(*perr)) { + goto err; + } + + *perr = ntlmssp_set_domain(ntlmssp_state, cli->domain); + if (!NT_STATUS_IS_OK(*perr)) { + goto err; + } + + if (cli->pwd.null_pwd) { + *perr = ntlmssp_set_password(ntlmssp_state, NULL); + if (!NT_STATUS_IS_OK(*perr)) { + goto err; + } + } else { + *perr = ntlmssp_set_password(ntlmssp_state, password); + if (!NT_STATUS_IS_OK(*perr)) { + goto err; + } + } + + /* Turn off sign+seal to allow selected auth level to turn it back on. */ + ntlmssp_state->neg_flags &= ~(NTLMSSP_NEGOTIATE_SIGN|NTLMSSP_NEGOTIATE_SEAL); + + if (auth_level == PIPE_AUTH_LEVEL_INTEGRITY) { + ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; + } else if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) { + ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL | NTLMSSP_NEGOTIATE_SIGN; + } + + *perr = rpc_pipe_bind(result, auth_type, auth_level); + if (!NT_STATUS_IS_OK(*perr)) { DEBUG(0, ("cli_rpc_pipe_open_ntlmssp_internal: cli_rpc_pipe_bind failed with error %s\n", - nt_errstr(status) )); + nt_errstr(*perr) )); goto err; } DEBUG(10,("cli_rpc_pipe_open_ntlmssp_internal: opened pipe %s to " "machine %s and bound NTLMSSP as user %s\\%s.\n", - result->trans.np.pipe_name, cli->desthost, + result->pipe_name, cli->desthost, domain, username )); - *presult = result; - return NT_STATUS_OK; + return result; err: - TALLOC_FREE(result); - return status; + cli_rpc_pipe_close(result); + return NULL; } /**************************************************************************** @@ -3071,22 +2386,22 @@ static NTSTATUS cli_rpc_pipe_open_ntlmssp_internal(struct cli_state *cli, Open a named pipe to an SMB server and bind using NTLMSSP (bind type 10) ****************************************************************************/ -NTSTATUS cli_rpc_pipe_open_ntlmssp(struct cli_state *cli, - const struct ndr_syntax_id *interface, - enum pipe_auth_level auth_level, - const char *domain, - const char *username, - const char *password, - struct rpc_pipe_client **presult) +struct rpc_pipe_client *cli_rpc_pipe_open_ntlmssp(struct cli_state *cli, + int pipe_idx, + enum pipe_auth_level auth_level, + const char *domain, + const char *username, + const char *password, + NTSTATUS *perr) { return cli_rpc_pipe_open_ntlmssp_internal(cli, - interface, + pipe_idx, PIPE_AUTH_TYPE_NTLMSSP, auth_level, domain, username, password, - presult); + perr); } /**************************************************************************** @@ -3094,36 +2409,36 @@ NTSTATUS cli_rpc_pipe_open_ntlmssp(struct cli_state *cli, Open a named pipe to an SMB server and bind using spnego NTLMSSP (bind type 9) ****************************************************************************/ -NTSTATUS cli_rpc_pipe_open_spnego_ntlmssp(struct cli_state *cli, - const struct ndr_syntax_id *interface, - enum pipe_auth_level auth_level, - const char *domain, - const char *username, - const char *password, - struct rpc_pipe_client **presult) +struct rpc_pipe_client *cli_rpc_pipe_open_spnego_ntlmssp(struct cli_state *cli, + int pipe_idx, + enum pipe_auth_level auth_level, + const char *domain, + const char *username, + const char *password, + NTSTATUS *perr) { return cli_rpc_pipe_open_ntlmssp_internal(cli, - interface, + pipe_idx, PIPE_AUTH_TYPE_SPNEGO_NTLMSSP, auth_level, domain, username, password, - presult); + perr); } /**************************************************************************** Get a the schannel session key out of an already opened netlogon pipe. ****************************************************************************/ -static NTSTATUS get_schannel_session_key_common(struct rpc_pipe_client *netlogon_pipe, - struct cli_state *cli, - const char *domain, - uint32 *pneg_flags) +static bool get_schannel_session_key_common(struct rpc_pipe_client *netlogon_pipe, + struct cli_state *cli, + const char *domain, + uint32 *pneg_flags, + NTSTATUS *perr) { uint32 sec_chan_type = 0; unsigned char machine_pwd[16]; const char *machine_account; - NTSTATUS status; /* Get the machine account credentials from secrets.tdb. */ if (!get_trust_pw_hash(domain, machine_pwd, &machine_account, @@ -3132,10 +2447,11 @@ static NTSTATUS get_schannel_session_key_common(struct rpc_pipe_client *netlogon DEBUG(0, ("get_schannel_session_key: could not fetch " "trust account password for domain '%s'\n", domain)); - return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + *perr = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + return false; } - status = rpccli_netlogon_setup_creds(netlogon_pipe, + *perr = rpccli_netlogon_setup_creds(netlogon_pipe, cli->desthost, /* server name */ domain, /* domain */ global_myname(), /* client name */ @@ -3144,22 +2460,21 @@ static NTSTATUS get_schannel_session_key_common(struct rpc_pipe_client *netlogon sec_chan_type, pneg_flags); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(3, ("get_schannel_session_key_common: " - "rpccli_netlogon_setup_creds failed with result %s " - "to server %s, domain %s, machine account %s.\n", - nt_errstr(status), cli->desthost, domain, - machine_account )); - return status; + if (!NT_STATUS_IS_OK(*perr)) { + DEBUG(3,("get_schannel_session_key_common: rpccli_netlogon_setup_creds " + "failed with result %s to server %s, domain %s, machine account %s.\n", + nt_errstr(*perr), cli->desthost, domain, machine_account )); + return false; } if (((*pneg_flags) & NETLOGON_NEG_SCHANNEL) == 0) { DEBUG(3, ("get_schannel_session_key: Server %s did not offer schannel\n", cli->desthost)); - return NT_STATUS_INVALID_NETWORK_RESPONSE; + *perr = NT_STATUS_INVALID_NETWORK_RESPONSE; + return false; } - return NT_STATUS_OK;; + return true; } /**************************************************************************** @@ -3168,29 +2483,26 @@ static NTSTATUS get_schannel_session_key_common(struct rpc_pipe_client *netlogon ****************************************************************************/ -NTSTATUS get_schannel_session_key(struct cli_state *cli, - const char *domain, - uint32 *pneg_flags, - struct rpc_pipe_client **presult) +struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli, + const char *domain, + uint32 *pneg_flags, + NTSTATUS *perr) { struct rpc_pipe_client *netlogon_pipe = NULL; - NTSTATUS status; - status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id, - &netlogon_pipe); - if (!NT_STATUS_IS_OK(status)) { - return status; + netlogon_pipe = cli_rpc_pipe_open_noauth(cli, PI_NETLOGON, perr); + if (!netlogon_pipe) { + return NULL; } - status = get_schannel_session_key_common(netlogon_pipe, cli, domain, - pneg_flags); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(netlogon_pipe); - return status; + if (!get_schannel_session_key_common(netlogon_pipe, cli, domain, + pneg_flags, perr)) + { + cli_rpc_pipe_close(netlogon_pipe); + return NULL; } - *presult = netlogon_pipe; - return NT_STATUS_OK; + return netlogon_pipe; } /**************************************************************************** @@ -3199,58 +2511,49 @@ NTSTATUS get_schannel_session_key(struct cli_state *cli, using session_key. sign and seal. ****************************************************************************/ -NTSTATUS cli_rpc_pipe_open_schannel_with_key(struct cli_state *cli, - const struct ndr_syntax_id *interface, - enum pipe_auth_level auth_level, - const char *domain, - const struct dcinfo *pdc, - struct rpc_pipe_client **presult) +struct rpc_pipe_client *cli_rpc_pipe_open_schannel_with_key(struct cli_state *cli, + int pipe_idx, + enum pipe_auth_level auth_level, + const char *domain, + const struct dcinfo *pdc, + NTSTATUS *perr) { struct rpc_pipe_client *result; - struct cli_pipe_auth_data *auth; - NTSTATUS status; - status = cli_rpc_pipe_open(cli, interface, &result); - if (!NT_STATUS_IS_OK(status)) { - return status; + result = cli_rpc_pipe_open(cli, pipe_idx, perr); + if (result == NULL) { + return NULL; } - status = rpccli_schannel_bind_data(result, domain, auth_level, - pdc->sess_key, &auth); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("rpccli_schannel_bind_data returned %s\n", - nt_errstr(status))); - TALLOC_FREE(result); - return status; + result->auth.a_u.schannel_auth = TALLOC_ZERO_P(result->mem_ctx, struct schannel_auth_struct); + if (!result->auth.a_u.schannel_auth) { + cli_rpc_pipe_close(result); + *perr = NT_STATUS_NO_MEMORY; + return NULL; } - status = rpc_pipe_bind(result, auth); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("cli_rpc_pipe_open_schannel_with_key: " - "cli_rpc_pipe_bind failed with error %s\n", - nt_errstr(status) )); - TALLOC_FREE(result); - return status; + result->domain = domain; + memcpy(result->auth.a_u.schannel_auth->sess_key, pdc->sess_key, 16); + + *perr = rpc_pipe_bind(result, PIPE_AUTH_TYPE_SCHANNEL, auth_level); + if (!NT_STATUS_IS_OK(*perr)) { + DEBUG(0, ("cli_rpc_pipe_open_schannel_with_key: cli_rpc_pipe_bind failed with error %s\n", + nt_errstr(*perr) )); + cli_rpc_pipe_close(result); + return NULL; } - /* - * The credentials on a new netlogon pipe are the ones we are passed - * in - copy them over. - */ - result->dc = (struct dcinfo *)talloc_memdup(result, pdc, sizeof(*pdc)); - if (result->dc == NULL) { - DEBUG(0, ("talloc failed\n")); - TALLOC_FREE(result); - return NT_STATUS_NO_MEMORY; + /* The credentials on a new netlogon pipe are the ones we are passed in - copy them over. */ + if (result->dc) { + *result->dc = *pdc; } DEBUG(10,("cli_rpc_pipe_open_schannel_with_key: opened pipe %s to machine %s " "for domain %s " "and bound using schannel.\n", - result->trans.np.pipe_name, cli->desthost, domain )); + result->pipe_name, cli->desthost, domain )); - *presult = result; - return NT_STATUS_OK; + return result; } /**************************************************************************** @@ -3259,32 +2562,28 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_key(struct cli_state *cli, version uses an ntlmssp auth bound netlogon pipe to get the key. ****************************************************************************/ -static NTSTATUS get_schannel_session_key_auth_ntlmssp(struct cli_state *cli, - const char *domain, - const char *username, - const char *password, - uint32 *pneg_flags, - struct rpc_pipe_client **presult) +static struct rpc_pipe_client *get_schannel_session_key_auth_ntlmssp(struct cli_state *cli, + const char *domain, + const char *username, + const char *password, + uint32 *pneg_flags, + NTSTATUS *perr) { struct rpc_pipe_client *netlogon_pipe = NULL; - NTSTATUS status; - status = cli_rpc_pipe_open_spnego_ntlmssp( - cli, &ndr_table_netlogon.syntax_id, PIPE_AUTH_LEVEL_PRIVACY, - domain, username, password, &netlogon_pipe); - if (!NT_STATUS_IS_OK(status)) { - return status; + netlogon_pipe = cli_rpc_pipe_open_spnego_ntlmssp(cli, PI_NETLOGON, PIPE_AUTH_LEVEL_PRIVACY, domain, username, password, perr); + if (!netlogon_pipe) { + return NULL; } - status = get_schannel_session_key_common(netlogon_pipe, cli, domain, - pneg_flags); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(netlogon_pipe); - return status; + if (!get_schannel_session_key_common(netlogon_pipe, cli, domain, + pneg_flags, perr)) + { + cli_rpc_pipe_close(netlogon_pipe); + return NULL; } - *presult = netlogon_pipe; - return NT_STATUS_OK; + return netlogon_pipe; } /**************************************************************************** @@ -3293,39 +2592,35 @@ static NTSTATUS get_schannel_session_key_auth_ntlmssp(struct cli_state *cli, uses an ntlmssp bind to get the session key. ****************************************************************************/ -NTSTATUS cli_rpc_pipe_open_ntlmssp_auth_schannel(struct cli_state *cli, - const struct ndr_syntax_id *interface, - enum pipe_auth_level auth_level, - const char *domain, - const char *username, - const char *password, - struct rpc_pipe_client **presult) +struct rpc_pipe_client *cli_rpc_pipe_open_ntlmssp_auth_schannel(struct cli_state *cli, + int pipe_idx, + enum pipe_auth_level auth_level, + const char *domain, + const char *username, + const char *password, + NTSTATUS *perr) { uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; struct rpc_pipe_client *netlogon_pipe = NULL; struct rpc_pipe_client *result = NULL; - NTSTATUS status; - status = get_schannel_session_key_auth_ntlmssp( - cli, domain, username, password, &neg_flags, &netlogon_pipe); - if (!NT_STATUS_IS_OK(status)) { + netlogon_pipe = get_schannel_session_key_auth_ntlmssp(cli, domain, username, + password, &neg_flags, perr); + if (!netlogon_pipe) { DEBUG(0,("cli_rpc_pipe_open_ntlmssp_auth_schannel: failed to get schannel session " "key from server %s for domain %s.\n", cli->desthost, domain )); - return status; + return NULL; } - status = cli_rpc_pipe_open_schannel_with_key( - cli, interface, auth_level, domain, netlogon_pipe->dc, - &result); + result = cli_rpc_pipe_open_schannel_with_key(cli, pipe_idx, + auth_level, + domain, netlogon_pipe->dc, perr); /* Now we've bound using the session key we can close the netlog pipe. */ - TALLOC_FREE(netlogon_pipe); + cli_rpc_pipe_close(netlogon_pipe); - if (NT_STATUS_IS_OK(status)) { - *presult = result; - } - return status; + return result; } /**************************************************************************** @@ -3333,122 +2628,109 @@ NTSTATUS cli_rpc_pipe_open_ntlmssp_auth_schannel(struct cli_state *cli, Fetch the session key ourselves using a temporary netlogon pipe. ****************************************************************************/ -NTSTATUS cli_rpc_pipe_open_schannel(struct cli_state *cli, - const struct ndr_syntax_id *interface, - enum pipe_auth_level auth_level, - const char *domain, - struct rpc_pipe_client **presult) +struct rpc_pipe_client *cli_rpc_pipe_open_schannel(struct cli_state *cli, + int pipe_idx, + enum pipe_auth_level auth_level, + const char *domain, + NTSTATUS *perr) { uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; struct rpc_pipe_client *netlogon_pipe = NULL; struct rpc_pipe_client *result = NULL; - NTSTATUS status; - status = get_schannel_session_key(cli, domain, &neg_flags, - &netlogon_pipe); - if (!NT_STATUS_IS_OK(status)) { + netlogon_pipe = get_schannel_session_key(cli, domain, &neg_flags, perr); + if (!netlogon_pipe) { DEBUG(0,("cli_rpc_pipe_open_schannel: failed to get schannel session " "key from server %s for domain %s.\n", cli->desthost, domain )); - return status; + return NULL; } - status = cli_rpc_pipe_open_schannel_with_key( - cli, interface, auth_level, domain, netlogon_pipe->dc, - &result); + result = cli_rpc_pipe_open_schannel_with_key(cli, pipe_idx, + auth_level, + domain, netlogon_pipe->dc, perr); /* Now we've bound using the session key we can close the netlog pipe. */ - TALLOC_FREE(netlogon_pipe); + cli_rpc_pipe_close(netlogon_pipe); - if (NT_STATUS_IS_OK(status)) { - *presult = result; - } + return result; +} - return NT_STATUS_OK; +#ifdef HAVE_KRB5 + +/**************************************************************************** + Free function for the kerberos spcific data. + ****************************************************************************/ + +static void kerberos_auth_struct_free(struct cli_pipe_auth_data *a) +{ + data_blob_free(&a->a_u.kerberos_auth->session_key); } +#endif + /**************************************************************************** Open a named pipe to an SMB server and bind using krb5 (bind type 16). The idea is this can be called with service_princ, username and password all NULL so long as the caller has a TGT. ****************************************************************************/ -NTSTATUS cli_rpc_pipe_open_krb5(struct cli_state *cli, - const struct ndr_syntax_id *interface, - enum pipe_auth_level auth_level, - const char *service_princ, - const char *username, - const char *password, - struct rpc_pipe_client **presult) +struct rpc_pipe_client *cli_rpc_pipe_open_krb5(struct cli_state *cli, + int pipe_idx, + enum pipe_auth_level auth_level, + const char *service_princ, + const char *username, + const char *password, + NTSTATUS *perr) { #ifdef HAVE_KRB5 struct rpc_pipe_client *result; - struct cli_pipe_auth_data *auth; - NTSTATUS status; - status = cli_rpc_pipe_open(cli, interface, &result); - if (!NT_STATUS_IS_OK(status)) { - return status; + result = cli_rpc_pipe_open(cli, pipe_idx, perr); + if (result == NULL) { + return NULL; } - status = rpccli_kerberos_bind_data(result, auth_level, service_princ, - username, password, &auth); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("rpccli_kerberos_bind_data returned %s\n", - nt_errstr(status))); - TALLOC_FREE(result); - return status; + /* Default service principal is "desthost$@realm" */ + if (!service_princ) { + service_princ = talloc_asprintf(result->mem_ctx, "%s$@%s", + cli->desthost, lp_realm() ); + if (!service_princ) { + cli_rpc_pipe_close(result); + return NULL; + } } - status = rpc_pipe_bind(result, auth); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("cli_rpc_pipe_open_krb5: cli_rpc_pipe_bind failed " - "with error %s\n", nt_errstr(status))); - TALLOC_FREE(result); - return status; + /* Only get a new TGT if username/password are given. */ + if (username && password) { + int ret = kerberos_kinit_password(username, password, 0, NULL); + if (ret) { + cli_rpc_pipe_close(result); + return NULL; + } } - *presult = result; - return NT_STATUS_OK; -#else - DEBUG(0,("cli_rpc_pipe_open_krb5: kerberos not found at compile time.\n")); - return NT_STATUS_NOT_IMPLEMENTED; -#endif -} - -NTSTATUS cli_get_session_key(TALLOC_CTX *mem_ctx, - struct rpc_pipe_client *cli, - DATA_BLOB *session_key) -{ - if (!session_key || !cli) { - return NT_STATUS_INVALID_PARAMETER; + result->auth.a_u.kerberos_auth = TALLOC_ZERO_P(result->mem_ctx, struct kerberos_auth_struct); + if (!result->auth.a_u.kerberos_auth) { + cli_rpc_pipe_close(result); + *perr = NT_STATUS_NO_MEMORY; + return NULL; } - if (!cli->auth) { - return NT_STATUS_INVALID_PARAMETER; - } + result->auth.a_u.kerberos_auth->service_principal = service_princ; + result->auth.cli_auth_data_free_func = kerberos_auth_struct_free; - switch (cli->auth->auth_type) { - case PIPE_AUTH_TYPE_SCHANNEL: - *session_key = data_blob_talloc(mem_ctx, - cli->auth->a_u.schannel_auth->sess_key, 16); - break; - case PIPE_AUTH_TYPE_NTLMSSP: - case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: - *session_key = data_blob_talloc(mem_ctx, - cli->auth->a_u.ntlmssp_state->session_key.data, - cli->auth->a_u.ntlmssp_state->session_key.length); - break; - case PIPE_AUTH_TYPE_KRB5: - case PIPE_AUTH_TYPE_SPNEGO_KRB5: - *session_key = data_blob_talloc(mem_ctx, - cli->auth->a_u.kerberos_auth->session_key.data, - cli->auth->a_u.kerberos_auth->session_key.length); - break; - case PIPE_AUTH_TYPE_NONE: - default: - return NT_STATUS_NO_USER_SESSION_KEY; + *perr = rpc_pipe_bind(result, PIPE_AUTH_TYPE_KRB5, auth_level); + if (!NT_STATUS_IS_OK(*perr)) { + DEBUG(0, ("cli_rpc_pipe_open_krb5: cli_rpc_pipe_bind failed with error %s\n", + nt_errstr(*perr) )); + cli_rpc_pipe_close(result); + return NULL; } - return NT_STATUS_OK; + return result; +#else + DEBUG(0,("cli_rpc_pipe_open_krb5: kerberos not found at compile time.\n")); + return NULL; +#endif } |