/*
- * Unix SMB/Netbios implementation.
- * Version 1.9.
+ * Unix SMB/CIFS implementation.
* RPC Pipe client / server routines
* Copyright (C) Andrew Tridgell 1992-1998,
* Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
#include "includes.h"
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_CLI
+
extern struct pipe_id_info pipe_names[];
-extern fstring global_myworkgroup;
-extern pstring global_myname;
/********************************************************************
Rpc pipe call id.
BOOL auth_verify = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SIGN) != 0);
BOOL auth_seal = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SEAL) != 0);
+ BOOL auth_schannel = (cli->saved_netlogon_pipe_fnum != 0);
- DEBUG(5,("rpc_auth_pipe: len: %d auth_len: %d verify %s seal %s\n",
- len, auth_len, BOOLSTR(auth_verify), BOOLSTR(auth_seal)));
+ DEBUG(5,("rpc_auth_pipe: len: %d auth_len: %d verify %s seal %s schannel %s\n",
+ len, auth_len, BOOLSTR(auth_verify), BOOLSTR(auth_seal), BOOLSTR(auth_schannel)));
/*
* Unseal any sealed data in the PDU, not including the
}
cli->ntlmssp_seq_num++;
}
+
+ if (auth_schannel) {
+ RPC_AUTH_NETSEC_CHK chk;
+ char data[RPC_AUTH_NETSEC_CHK_LEN];
+ char *dp = prs_data_p(rdata) + len - auth_len;
+ prs_struct auth_verf;
+
+ if (auth_len != RPC_AUTH_NETSEC_CHK_LEN) {
+ DEBUG(0,("rpc_auth_pipe: wrong schannel auth len %d\n", auth_len));
+ return False;
+ }
+
+ if (dp - prs_data_p(rdata) > prs_data_size(rdata)) {
+ DEBUG(0,("rpc_auth_pipe: schannel auth data > data size !\n"));
+ return False;
+ }
+
+ DEBUG(10,("rpc_auth_pipe: schannel verify netsec\n"));
+ dump_data(100, dp, auth_len);
+
+ memcpy(data, dp, sizeof(data));
+ dump_data(100, data, sizeof(data));
+
+ prs_init(&auth_verf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* The endinness must be preserved. JRA. */
+ prs_set_endian_data( &auth_verf, rdata->bigendian_data);
+
+ prs_give_memory(&auth_verf, data, RPC_AUTH_NETSEC_CHK_LEN, False);
+
+ if (!smb_io_rpc_auth_netsec_chk("schannel_auth_sign", &chk, &auth_verf, 0)) {
+ DEBUG(0, ("rpc_auth_pipe: schannel unmarshalling "
+ "RPC_AUTH_NETSECK_CHK failed\n"));
+ return False;
+ }
+
+ cli->auth_info.seq_num++;
+
+ if (!netsec_decode(&cli->auth_info, &chk, reply_data, data_len)) {
+ DEBUG(0, ("rpc_auth_pipe: Could not decode schannel\n"));
+ return False;
+ }
+ }
return True;
}
/****************************************************************************
- Send data on an rpc pipe, which *must* be in one fragment.
+ Send data on an rpc pipe via trans, which *must* be the last fragment.
receive response data from an rpc pipe, which may be large...
Read the first fragment: unfortunately have to use SMBtrans for the first
+------------+-----------------+-------------+---------------+-------------+
Where the presence of the AUTH_HDR and AUTH are dependent on the
- signing & sealing being neogitated.
+ signing & sealing being negotiated.
****************************************************************************/
-static BOOL rpc_api_pipe(struct cli_state *cli, uint16 cmd, prs_struct *data, prs_struct *rdata)
+static BOOL rpc_api_pipe(struct cli_state *cli, prs_struct *data, prs_struct *rdata)
{
uint32 len;
char *rparam = NULL;
char *prdata = NULL;
uint32 rdata_len = 0;
uint32 current_offset = 0;
+ uint32 max_data = cli->max_xmit_frag ? cli->max_xmit_frag : 1024;
/* Create setup parameters - must be in native byte order. */
- setup[0] = cmd;
+ setup[0] = TRANSACT_DCERPCCMD;
setup[1] = cli->nt_pipe_fnum; /* Pipe file handle. */
- DEBUG(5,("rpc_api_pipe: cmd:%x fnum:%x\n", (int)cmd,
- (int)cli->nt_pipe_fnum));
+ DEBUG(5,("rpc_api_pipe: fnum:%x\n", (int)cli->nt_pipe_fnum));
/* Send the RPC request and receive a response. For short RPC
calls (about 1024 bytes or so) the RPC request and response
if (!cli_api_pipe(cli, "\\PIPE\\",
setup, 2, 0, /* Setup, length, max */
NULL, 0, 0, /* Params, length, max */
- pdata, data_len, data_len, /* data, length, max */
+ pdata, data_len, max_data, /* data, length, max */
&rparam, &rparam_len, /* return params, len */
&prdata, &rdata_len)) /* return data, len */
{
SAFE_FREE(rparam);
if (prdata == NULL) {
- DEBUG(0,("rpc_api_pipe: cmd %x on pipe %x failed to return data.\n",
- (int)cmd, (int)cli->nt_pipe_fnum));
+ DEBUG(0,("rpc_api_pipe: pipe %x failed to return data.\n",
+ (int)cli->nt_pipe_fnum));
return False;
}
********************************************************************/
-static BOOL create_rpc_bind_req(prs_struct *rpc_out, BOOL do_auth, uint32 rpc_call_id,
+static BOOL create_rpc_bind_req(prs_struct *rpc_out, BOOL do_auth, BOOL do_netsec, uint32 rpc_call_id,
RPC_IFACE *abstract, RPC_IFACE *transfer,
- char *my_name, char *domain, uint32 neg_flags)
+ const char *my_name, const char *domain, uint32 neg_flags)
{
RPC_HDR hdr;
RPC_HDR_RB hdr_rb;
auth_len = prs_offset(&auth_info) - RPC_HDR_AUTH_LEN;
}
+ if (do_netsec) {
+ RPC_HDR_AUTH hdr_auth;
+ RPC_AUTH_NETSEC_NEG netsec_neg;
+
+ /*
+ * Create the auth structs we will marshall.
+ */
+
+ init_rpc_hdr_auth(&hdr_auth, NETSEC_AUTH_TYPE, NETSEC_AUTH_LEVEL,
+ 0x00, 1);
+ init_rpc_auth_netsec_neg(&netsec_neg, domain, my_name);
+
+ /*
+ * Use the 4k buffer to store the auth info.
+ */
+
+ prs_give_memory( &auth_info, buffer, sizeof(buffer), False);
+
+ /*
+ * Now marshall the data into the temporary parse_struct.
+ */
+
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, &auth_info, 0)) {
+ DEBUG(0,("Failed to marshall RPC_HDR_AUTH.\n"));
+ return False;
+ }
+
+ if(!smb_io_rpc_auth_netsec_neg("netsec_neg",
+ &netsec_neg, &auth_info, 0)) {
+ DEBUG(0,("Failed to marshall RPC_AUTH_NETSEC_NEG.\n"));
+ return False;
+ }
+
+ /* Auth len in the rpc header doesn't include auth_header. */
+ auth_len = prs_offset(&auth_info) - RPC_HDR_AUTH_LEN;
+ }
+
/* create the request RPC_HDR */
- init_rpc_hdr(&hdr, RPC_BIND, 0x0, rpc_call_id,
+ init_rpc_hdr(&hdr, RPC_BIND, 0x3, rpc_call_id,
RPC_HEADER_LEN + RPC_HDR_RB_LEN + prs_offset(&auth_info),
auth_len);
********************************************************************/
static BOOL create_rpc_bind_resp(struct pwd_info *pwd,
- char *domain, char *user_name, char *my_name,
+ const char *domain, const char *user_name, const char *my_name,
uint32 ntlmssp_cli_flgs,
uint32 rpc_call_id,
prs_struct *rpc_out)
Creates a DCE/RPC request.
********************************************************************/
-static BOOL create_rpc_request(prs_struct *rpc_out, uint8 op_num, int data_len, int auth_len)
+static uint32 create_rpc_request(prs_struct *rpc_out, uint8 op_num, int data_len, int auth_len, uint8 flags, uint32 oldid, uint32 data_left)
{
uint32 alloc_hint;
RPC_HDR hdr;
RPC_HDR_REQ hdr_req;
+ uint32 callid = oldid ? oldid : get_rpc_call_id();
DEBUG(5,("create_rpc_request: opnum: 0x%x data_len: 0x%x\n", op_num, data_len));
/* create the rpc header RPC_HDR */
- init_rpc_hdr(&hdr, RPC_REQUEST, RPC_FLG_FIRST | RPC_FLG_LAST,
- get_rpc_call_id(), data_len, auth_len);
+ init_rpc_hdr(&hdr, RPC_REQUEST, flags,
+ callid, data_len, auth_len);
/*
* The alloc hint should be the amount of data, not including
/* stream-time... */
if(!smb_io_rpc_hdr("hdr ", &hdr, rpc_out, 0))
- return False;
+ return 0;
if(!smb_io_rpc_hdr_req("hdr_req", &hdr_req, rpc_out, 0))
- return False;
+ return 0;
if (prs_offset(rpc_out) != RPC_HEADER_LEN + RPC_HDR_REQ_LEN)
+ return 0;
+
+ return callid;
+}
+
+/*******************************************************************
+ Puts an NTLMSSP auth header into an rpc request.
+ ********************************************************************/
+
+static BOOL create_ntlmssp_auth_hdr(prs_struct *outgoing_packet, BOOL auth_verify)
+{
+ RPC_HDR_AUTH hdr_auth;
+
+ init_rpc_hdr_auth(&hdr_auth, NTLMSSP_AUTH_TYPE,
+ NTLMSSP_AUTH_LEVEL, 0x08,
+ (auth_verify ? 1 : 0));
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth,
+ outgoing_packet, 0)) {
+ DEBUG(0,("create_auth_hdr:Failed to marshal RPC_HDR_AUTH.\n"));
return False;
+ }
+ return True;
+}
+
+/*******************************************************************
+ Puts a NETLOGON schannel auth header into an rpc request.
+ ********************************************************************/
+static BOOL create_netsec_auth_hdr(prs_struct *outgoing_packet, int padding)
+{
+ RPC_HDR_AUTH hdr_auth;
+
+ init_rpc_hdr_auth(&hdr_auth, NETSEC_AUTH_TYPE,
+ NETSEC_AUTH_LEVEL, padding, 1);
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth,
+ outgoing_packet, 0)) {
+ DEBUG(0,("create_auth_hdr:Failed to marshal RPC_HDR_AUTH.\n"));
+ return False;
+ }
return True;
}
+/*******************************************************************
+ Puts auth data into an rpc request.
+ ********************************************************************/
-/****************************************************************************
- Send a request on an rpc pipe.
- ****************************************************************************/
+static BOOL create_auth_data(struct cli_state *cli, uint32 crc32,
+ prs_struct *outgoing_packet)
+{
+ char *pdata_out = prs_data_p(outgoing_packet);
+ RPC_AUTH_NTLMSSP_CHK chk;
+ uint32 current_offset = prs_offset(outgoing_packet);
+
+ init_rpc_auth_ntlmssp_chk(&chk, NTLMSSP_SIGN_VERSION,
+ crc32, cli->ntlmssp_seq_num++);
+ if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &chk,
+ outgoing_packet, 0)) {
+ DEBUG(0,("create_auth_data: Failed to marshal RPC_AUTH_NTLMSSP_CHK.\n"));
+ return False;
+ }
+ NTLMSSPcalc_ap(cli, (unsigned char*)
+ &pdata_out[current_offset+4],
+ RPC_AUTH_NTLMSSP_CHK_LEN - 4);
+ return True;
+}
+
+/**
+ * Send a request on an RPC pipe and get a response.
+ *
+ * @param data NDR contents of the request to be sent.
+ * @param rdata Unparsed NDR response data.
+**/
BOOL rpc_api_pipe_req(struct cli_state *cli, uint8 op_num,
prs_struct *data, prs_struct *rdata)
{
- prs_struct outgoing_packet;
- uint32 data_len;
- uint32 auth_len;
- BOOL ret;
- BOOL auth_verify;
- BOOL auth_seal;
- uint32 crc32 = 0;
- char *pdata_out = NULL;
+ uint32 auth_len, max_data, data_left, data_sent;
+ BOOL ret = False;
+ BOOL auth_verify, auth_seal, auth_schannel;
+ uint32 callid = 0;
+ fstring dump_name;
auth_verify = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SIGN) != 0);
auth_seal = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SEAL) != 0);
+ auth_schannel = (cli->saved_netlogon_pipe_fnum != 0);
- /*
- * The auth_len doesn't include the RPC_HDR_AUTH_LEN.
- */
+ auth_len = 0;
+
+ if (auth_verify)
+ auth_len = RPC_AUTH_NTLMSSP_CHK_LEN;
- auth_len = (auth_verify ? RPC_AUTH_NTLMSSP_CHK_LEN : 0);
+ if (auth_schannel)
+ auth_len = RPC_AUTH_NETSEC_CHK_LEN;
/*
- * PDU len is header, plus request header, plus data, plus
- * auth_header_len (if present), plus auth_len (if present).
- * NB. The auth stuff should be aligned on an 8 byte boundary
- * to be totally DCE/RPC spec complient. For now we cheat and
- * hope that the data structs defined are a multiple of 8 bytes.
+ * calc how much actual data we can send in a PDU fragment
*/
+ max_data = cli->max_xmit_frag - RPC_HEADER_LEN - RPC_HDR_REQ_LEN -
+ (auth_verify ? RPC_HDR_AUTH_LEN : 0) - auth_len - 8;
- if((prs_offset(data) % 8) != 0) {
- DEBUG(5,("rpc_api_pipe_req: Outgoing data not a multiple of 8 bytes....\n"));
- }
+ for (data_left = prs_offset(data), data_sent = 0; data_left > 0;) {
+ prs_struct outgoing_packet;
+ uint32 data_len, send_size;
+ uint8 flags = 0;
+ uint32 crc32 = 0;
+ uint32 auth_padding = 0;
+ RPC_AUTH_NETSEC_CHK verf;
- data_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN + prs_offset(data) +
- (auth_verify ? RPC_HDR_AUTH_LEN : 0) + auth_len;
+ /*
+ * how much will we send this time
+ */
+ send_size = MIN(data_left, max_data);
- /*
- * Malloc a parse struct to hold it (and enough for alignments).
- */
+ /*
+ * NT expects the data that is sealed to be 8-byte
+ * aligned. The padding must be encrypted as well and
+ * taken into account when generating the
+ * authentication verifier. The amount of padding must
+ * be stored in the auth header.
+ */
- if(!prs_init(&outgoing_packet, data_len + 8, cli->mem_ctx, MARSHALL)) {
- DEBUG(0,("rpc_api_pipe_req: Failed to malloc %u bytes.\n", (unsigned int)data_len ));
- return False;
- }
+ if (auth_schannel)
+ auth_padding = 8 - (send_size & 7);
- pdata_out = prs_data_p(&outgoing_packet);
-
- /*
- * Write out the RPC header and the request header.
- */
+ data_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN + send_size +
+ ((auth_verify|auth_schannel) ? RPC_HDR_AUTH_LEN : 0) +
+ auth_len + auth_padding;
- if(!create_rpc_request(&outgoing_packet, op_num, data_len, auth_len)) {
- DEBUG(0,("rpc_api_pipe_req: Failed to create RPC request.\n"));
- prs_mem_free(&outgoing_packet);
- return False;
- }
+ /*
+ * Malloc parse struct to hold it (and enough for alignments).
+ */
+ if(!prs_init(&outgoing_packet, data_len + 8,
+ cli->mem_ctx, MARSHALL)) {
+ DEBUG(0,("rpc_api_pipe_req: Failed to malloc %u bytes.\n", (unsigned int)data_len ));
+ return False;
+ }
- /*
- * Seal the outgoing data if requested.
- */
+ if (data_left == prs_offset(data))
+ flags |= RPC_FLG_FIRST;
- if (auth_seal) {
- crc32 = crc32_calc_buffer(prs_data_p(data), prs_offset(data));
- NTLMSSPcalc_ap(cli, (unsigned char*)prs_data_p(data), prs_offset(data));
- }
+ if (data_left <= max_data)
+ flags |= RPC_FLG_LAST;
+ /*
+ * Write out the RPC header and the request header.
+ */
+ if(!(callid = create_rpc_request(&outgoing_packet, op_num,
+ data_len, auth_len, flags,
+ callid, data_left))) {
+ DEBUG(0,("rpc_api_pipe_req: Failed to create RPC request.\n"));
+ prs_mem_free(&outgoing_packet);
+ return False;
+ }
- /*
- * Now copy the data into the outgoing packet.
- */
+ /*
+ * Seal the outgoing data if requested.
+ */
+ if (auth_seal) {
+ crc32 = crc32_calc_buffer(prs_data_p(data) + data_sent,
+ send_size);
+ NTLMSSPcalc_ap(cli, (unsigned char*)prs_data_p(data) +
+ data_sent, send_size);
+ }
- if(!prs_append_prs_data( &outgoing_packet, data)) {
- DEBUG(0,("rpc_api_pipe_req: Failed to append data to outgoing packet.\n"));
- prs_mem_free(&outgoing_packet);
- return False;
- }
+ /*
+ * Now copy the data into the outgoing packet.
+ */
- /*
- * Add a trailing auth_verifier if needed.
- */
+ if (auth_schannel) {
+ static const uchar netsec_sig[8] = NETSEC_SIGNATURE;
+ static const uchar nullbytes[8] = { 0,0,0,0,0,0,0,0 };
+ uchar sign[8];
+ prs_struct netsec_blob;
- if (auth_seal || auth_verify) {
- RPC_HDR_AUTH hdr_auth;
+ if ((cli->auth_info.seq_num & 1) != 0) {
+ DEBUG(0,("SCHANNEL ERROR: seq_num must be even in client (seq_num=%d)\n",
+ cli->auth_info.seq_num));
+ }
- init_rpc_hdr_auth(&hdr_auth, NTLMSSP_AUTH_TYPE,
- NTLMSSP_AUTH_LEVEL, 0x08, (auth_verify ? 1 : 0));
- if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, &outgoing_packet, 0)) {
- DEBUG(0,("rpc_api_pipe_req: Failed to marshal RPC_HDR_AUTH.\n"));
- prs_mem_free(&outgoing_packet);
- return False;
- }
- }
+ DEBUG(10,("SCHANNEL seq_num=%d\n", cli->auth_info.seq_num));
- /*
- * Finally the auth data itself.
- */
+ RSIVAL(sign, 0, cli->auth_info.seq_num);
+ SIVAL(sign, 4, 0x80);
- if (auth_verify) {
- RPC_AUTH_NTLMSSP_CHK chk;
- uint32 current_offset = prs_offset(&outgoing_packet);
+ if (!prs_init(&netsec_blob, send_size+auth_padding,
+ cli->mem_ctx, MARSHALL)) {
+ DEBUG(0,("Could not malloc %u bytes",
+ send_size+auth_padding));
+ prs_mem_free(&outgoing_packet);
+ return False;
+ }
- init_rpc_auth_ntlmssp_chk(&chk, NTLMSSP_SIGN_VERSION, crc32, cli->ntlmssp_seq_num++);
- if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &chk, &outgoing_packet, 0)) {
- DEBUG(0,("rpc_api_pipe_req: Failed to marshal RPC_AUTH_NTLMSSP_CHK.\n"));
- prs_mem_free(&outgoing_packet);
- return False;
+ if(!prs_append_some_prs_data(&netsec_blob, data,
+ data_sent, send_size)) {
+ DEBUG(0,("Failed to append data to netsec blob\n"));
+ prs_mem_free(&outgoing_packet);
+ return False;
+ }
+
+ netsec_blob.align = 8;
+
+ if (!prs_align(&netsec_blob)) {
+ DEBUG(0,("Could not align netsec blob\n"));
+ prs_mem_free(&outgoing_packet);
+ return False;
+ }
+
+ init_rpc_auth_netsec_chk(&verf, netsec_sig, nullbytes,
+ sign, nullbytes);
+
+ netsec_encode(&cli->auth_info, &verf,
+ prs_data_p(&netsec_blob),
+ prs_data_size(&netsec_blob));
+
+ prs_append_prs_data(&outgoing_packet, &netsec_blob);
+ prs_mem_free(&netsec_blob);
+
+ cli->auth_info.seq_num++;
+
+ } else {
+ if(!prs_append_some_prs_data(&outgoing_packet, data,
+ data_sent, send_size)) {
+ DEBUG(0,("rpc_api_pipe_req: Failed to append "
+ "data to outgoing packet.\n"));
+ prs_mem_free(&outgoing_packet);
+ return False;
+ }
+ }
+
+ /*
+ * Add a trailing auth_verifier if needed.
+ */
+ if (auth_seal || auth_verify) {
+ if(!create_ntlmssp_auth_hdr(&outgoing_packet, auth_verify)) {
+ prs_mem_free(&outgoing_packet);
+ return False;
+ }
+ }
+
+ /*
+ * Finally the auth data itself.
+ */
+ if (auth_verify) {
+ if (!create_auth_data(cli, crc32, &outgoing_packet)) {
+ prs_mem_free(&outgoing_packet);
+ return False;
+ }
}
- NTLMSSPcalc_ap(cli, (unsigned char*)&pdata_out[current_offset+4], RPC_AUTH_NTLMSSP_CHK_LEN - 4);
- }
- DEBUG(100,("data_len: %x data_calc_len: %x\n", data_len, prs_offset(&outgoing_packet)));
+ if (auth_schannel) {
- ret = rpc_api_pipe(cli, 0x0026, &outgoing_packet, rdata);
+ if (!create_netsec_auth_hdr(&outgoing_packet,
+ auth_padding)) {
+ prs_mem_free(&outgoing_packet);
+ return False;
+ }
+
+ if (!smb_io_rpc_auth_netsec_chk("", &verf,
+ &outgoing_packet, 0)) {
+ prs_mem_free(&outgoing_packet);
+ return False;
+ }
+ }
- prs_mem_free(&outgoing_packet);
+ DEBUG(100,("data_len: %x data_calc_len: %x\n", data_len,
+ prs_offset(&outgoing_packet)));
+
+ if (flags & RPC_FLG_LAST)
+ ret = rpc_api_pipe(cli, &outgoing_packet, rdata);
+ else {
+ cli_write(cli, cli->nt_pipe_fnum, 0x0008,
+ prs_data_p(&outgoing_packet),
+ data_sent, data_len);
+ }
+ prs_mem_free(&outgoing_packet);
+ data_sent += send_size;
+ data_left -= send_size;
+ }
+ /* Also capture received data */
+ slprintf(dump_name, sizeof(dump_name) - 1, "reply_%s",
+ cli_pipe_get_name(cli));
+ prs_dump(dump_name, op_num, rdata);
return ret;
}
check the rpc bind acknowledge response
****************************************************************************/
-static BOOL valid_pipe_name(const char *pipe_name, RPC_IFACE *abstract, RPC_IFACE *transfer)
+int get_pipe_index( const char *pipe_name )
{
int pipe_idx = 0;
while (pipe_names[pipe_idx].client_pipe != NULL) {
- if (strequal(pipe_name, pipe_names[pipe_idx].client_pipe )) {
- DEBUG(5,("Bind Abstract Syntax: "));
- dump_data(5, (char*)&(pipe_names[pipe_idx].abstr_syntax),
- sizeof(pipe_names[pipe_idx].abstr_syntax));
- DEBUG(5,("Bind Transfer Syntax: "));
- dump_data(5, (char*)&(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;
- }
+ if (strequal(pipe_name, pipe_names[pipe_idx].client_pipe ))
+ return pipe_idx;
pipe_idx++;
};
- DEBUG(5,("Bind RPC Pipe[%s] unsupported\n", pipe_name));
+ return -1;
+}
+
+
+/****************************************************************************
+ check the rpc bind acknowledge response
+****************************************************************************/
+
+const char* get_pipe_name_from_index( const int pipe_index )
+{
+
+ if ( (pipe_index < 0) || (pipe_index >= PI_MAX_PIPES) )
+ return NULL;
+
+ return pipe_names[pipe_index].client_pipe;
+}
+
+/****************************************************************************
+ Check to see if this pipe index points to one of
+ the pipes only supported by Win2k
+ ****************************************************************************/
+
+BOOL is_win2k_pipe( const int pipe_idx )
+{
+ switch ( pipe_idx )
+ {
+ case PI_LSARPC_DS:
+ return True;
+ }
+
return False;
}
check the rpc bind acknowledge response
****************************************************************************/
-static BOOL check_bind_response(RPC_HDR_BA *hdr_ba, const char *pipe_name, 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, (char*)&(pipe_names[pipe_idx].abstr_syntax),
+ sizeof(pipe_names[pipe_idx].abstr_syntax));
+ DEBUG(5,("Bind Transfer Syntax: "));
+ dump_data(5, (char*)&(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)
{
int i = 0;
- while ((pipe_names[i].client_pipe != NULL) && hdr_ba->addr.len > 0) {
- if ((strequal(pipe_name, pipe_names[i].client_pipe ))) {
- if (strequal(hdr_ba->addr.str, pipe_names[i].server_pipe )) {
- DEBUG(5,("bind_rpc_pipe: server pipe_name found: %s\n",
- pipe_names[i].server_pipe ));
- break;
- } else {
- DEBUG(4,("bind_rpc_pipe: pipe_name %s != expected pipe %s. oh well!\n",
- pipe_names[i].server_pipe ,
- hdr_ba->addr.str));
- break;
- }
- } else {
- i++;
- }
+ if ( hdr_ba->addr.len <= 0)
+ return False;
+
+ if ( !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[i].server_pipe == NULL) {
+ if (pipe_names[pipe_idx].server_pipe == NULL) {
DEBUG(2,("bind_rpc_pipe: pipe name %s unsupported\n", hdr_ba->addr.str));
return False;
}
/* check the transfer syntax */
if ((hdr_ba->transfer.version != transfer->version) ||
(memcmp(&hdr_ba->transfer.uuid, &transfer->uuid, sizeof(transfer->uuid)) !=0)) {
- DEBUG(0,("bind_rpc_pipe: transfer syntax differs\n"));
+ DEBUG(2,("bind_rpc_pipe: transfer syntax differs\n"));
return False;
}
prs_give_memory( &rpc_out, buffer, sizeof(buffer), False);
create_rpc_bind_resp(&cli->pwd, cli->domain,
- cli->user_name, global_myname,
+ cli->user_name, global_myname(),
cli->ntlmssp_cli_flgs, rpc_call_id,
&rpc_out);
Do an rpc bind.
****************************************************************************/
-BOOL rpc_pipe_bind(struct cli_state *cli, const char *pipe_name, char *my_name)
+static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_name,
+ BOOL do_netsec)
{
RPC_IFACE abstract;
RPC_IFACE transfer;
uint32 rpc_call_id;
char buffer[MAX_PDU_FRAG_LEN];
- DEBUG(5,("Bind RPC Pipe[%x]: %s\n", cli->nt_pipe_fnum, pipe_name));
+ if ( (pipe_idx < 0) || (pipe_idx >= PI_MAX_PIPES) )
+ return False;
- if (!valid_pipe_name(pipe_name, &abstract, &transfer))
+ DEBUG(5,("Bind RPC Pipe[%x]: %s\n", cli->nt_pipe_fnum, pipe_names[pipe_idx].client_pipe));
+
+ if (!valid_pipe_name(pipe_idx, &abstract, &transfer))
return False;
prs_init(&rpc_out, 0, cli->mem_ctx, MARSHALL);
rpc_call_id = get_rpc_call_id();
/* Marshall the outgoing data. */
- create_rpc_bind_req(&rpc_out, do_auth, rpc_call_id,
+ create_rpc_bind_req(&rpc_out, do_auth, do_netsec, rpc_call_id,
&abstract, &transfer,
- global_myname, cli->domain, cli->ntlmssp_cli_flgs);
+ global_myname(), cli->domain, cli->ntlmssp_cli_flgs);
/* Initialize the incoming data struct. */
prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
/* send data on \PIPE\. receive a response */
- if (rpc_api_pipe(cli, 0x0026, &rpc_out, &rdata)) {
+ if (rpc_api_pipe(cli, &rpc_out, &rdata)) {
RPC_HDR_BA hdr_ba;
DEBUG(5, ("rpc_pipe_bind: rpc_api_pipe returned OK.\n"));
return False;
}
- if(!check_bind_response(&hdr_ba, pipe_name, &transfer)) {
- DEBUG(0,("rpc_pipe_bind: check_bind_response failed.\n"));
+ if(!check_bind_response(&hdr_ba, pipe_idx, &transfer)) {
+ DEBUG(2,("rpc_pipe_bind: check_bind_response failed.\n"));
prs_mem_free(&rdata);
return False;
}
return True;
}
-/****************************************************************************
- Set ntlmssp negotiation flags.
- ****************************************************************************/
-
-void cli_nt_set_ntlmssp_flgs(struct cli_state *cli, uint32 ntlmssp_flgs)
-{
- cli->ntlmssp_cli_flgs = ntlmssp_flgs;
-}
-
-
/****************************************************************************
Open a session.
****************************************************************************/
-BOOL cli_nt_session_open(struct cli_state *cli, const char *pipe_name)
+BOOL cli_nt_session_open(struct cli_state *cli, const int pipe_idx)
{
int fnum;
+ /* At the moment we can't have more than one pipe open over
+ a cli connection. )-: */
+
SMB_ASSERT(cli->nt_pipe_fnum == 0);
+
+ /* The pipe index must fall within our array */
+
+ SMB_ASSERT((pipe_idx >= 0) && (pipe_idx < PI_MAX_PIPES));
if (cli->capabilities & CAP_NT_SMBS) {
- if ((fnum = cli_nt_create(cli, &pipe_name[5], DESIRED_ACCESS_PIPE)) == -1) {
+ if ((fnum = cli_nt_create(cli, &pipe_names[pipe_idx].client_pipe[5], DESIRED_ACCESS_PIPE)) == -1) {
DEBUG(0,("cli_nt_session_open: cli_nt_create failed on pipe %s to machine %s. Error was %s\n",
- &pipe_name[5], cli->desthost, cli_errstr(cli)));
+ &pipe_names[pipe_idx].client_pipe[5], cli->desthost, cli_errstr(cli)));
return False;
}
cli->nt_pipe_fnum = (uint16)fnum;
} else {
- if ((fnum = cli_open(cli, pipe_name, O_CREAT|O_RDWR, DENY_NONE)) == -1) {
+ if ((fnum = cli_open(cli, pipe_names[pipe_idx].client_pipe, O_CREAT|O_RDWR, DENY_NONE)) == -1) {
DEBUG(0,("cli_nt_session_open: cli_open failed on pipe %s to machine %s. Error was %s\n",
- pipe_name, cli->desthost, cli_errstr(cli)));
+ pipe_names[pipe_idx].client_pipe, cli->desthost, cli_errstr(cli)));
return False;
}
cli->nt_pipe_fnum = (uint16)fnum;
/**************** Set Named Pipe State ***************/
- if (!rpc_pipe_set_hnd_state(cli, pipe_name, 0x4300)) {
+ if (!rpc_pipe_set_hnd_state(cli, pipe_names[pipe_idx].client_pipe, 0x4300)) {
DEBUG(0,("cli_nt_session_open: pipe hnd state failed. Error was %s\n",
cli_errstr(cli)));
cli_close(cli, cli->nt_pipe_fnum);
/******************* bind request on pipe *****************/
- if (!rpc_pipe_bind(cli, pipe_name, global_myname)) {
- DEBUG(0,("cli_nt_session_open: rpc bind failed. Error was %s\n",
- cli_errstr(cli)));
+ if (!rpc_pipe_bind(cli, pipe_idx, global_myname(), False)) {
+ DEBUG(2,("cli_nt_session_open: rpc bind to %s failed\n",
+ get_pipe_name_from_index(pipe_idx)));
cli_close(cli, cli->nt_pipe_fnum);
return False;
}
strupper(cli->srv_name_slash);
fstrcpy(cli->clnt_name_slash, "\\\\");
- fstrcat(cli->clnt_name_slash, global_myname);
+ fstrcat(cli->clnt_name_slash, global_myname());
strupper(cli->clnt_name_slash);
- fstrcpy(cli->mach_acct, global_myname);
+ fstrcpy(cli->mach_acct, global_myname());
fstrcat(cli->mach_acct, "$");
strupper(cli->mach_acct);
+ /* Remember which pipe we're talking to */
+ fstrcpy(cli->pipe_name, pipe_names[pipe_idx].client_pipe);
+
+ return True;
+}
+
+
+/****************************************************************************
+ Open a session to the NETLOGON pipe using schannel.
+ ****************************************************************************/
+
+BOOL cli_nt_open_netlogon(struct cli_state *cli, const char *trust_password,
+ int sec_chan)
+{
+ NTSTATUS result;
+ uint32 neg_flags = 0x000001ff;
+ int fnum;
+
+ if (lp_client_schannel() != False)
+ neg_flags |= NETLOGON_NEG_SCHANNEL;
+
+
+ if (!cli_nt_session_open(cli, PI_NETLOGON)) {
+ return False;
+ }
+
+ if (!secrets_init()) {
+ DEBUG(3,("Failed to init secrets.tdb\n"));
+ return False;
+ }
+
+ result = cli_nt_setup_creds(cli, sec_chan, trust_password,
+ &neg_flags, 2);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ cli_nt_session_close(cli);
+ return False;
+ }
+
+ if ((lp_client_schannel() == True) &&
+ ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
+
+ DEBUG(3, ("Server did not offer schannel\n"));
+ cli_nt_session_close(cli);
+ return False;
+ }
+
+ if ((lp_client_schannel() == False) ||
+ ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
+ return True;
+ }
+
+ /* Server offered schannel, so try it. */
+
+ cli->auth_info.seq_num = 0;
+ memcpy(cli->auth_info.sess_key, cli->sess_key,
+ sizeof(cli->auth_info.sess_key));
+
+ cli->saved_netlogon_pipe_fnum = cli->nt_pipe_fnum;
+
+ if (cli->capabilities & CAP_NT_SMBS) {
+
+ /* The secure channel connection must be opened on the same
+ session (TCP connection) as the one the challenge was
+ requested from. */
+
+ if ((fnum = cli_nt_create(cli, PIPE_NETLOGON_PLAIN,
+ DESIRED_ACCESS_PIPE)) == -1) {
+ DEBUG(0,("cli_nt_create failed to %s machine %s. "
+ "Error was %s\n",
+ PIPE_NETLOGON, cli->desthost,
+ cli_errstr(cli)));
+ return False;
+ }
+
+ cli->nt_pipe_fnum = (uint16)fnum;
+ } else {
+ if ((fnum = cli_open(cli, PIPE_NETLOGON,
+ O_CREAT|O_RDWR, DENY_NONE)) == -1) {
+ DEBUG(0,("cli_open failed on pipe %s to machine %s. "
+ "Error was %s\n",
+ PIPE_NETLOGON, cli->desthost,
+ cli_errstr(cli)));
+ return False;
+ }
+
+ cli->nt_pipe_fnum = (uint16)fnum;
+
+ /**************** Set Named Pipe State ***************/
+ if (!rpc_pipe_set_hnd_state(cli, PIPE_NETLOGON, 0x4300)) {
+ DEBUG(0,("Pipe hnd state failed. Error was %s\n",
+ cli_errstr(cli)));
+ cli_close(cli, cli->nt_pipe_fnum);
+ return False;
+ }
+ }
+
+ if (!rpc_pipe_bind(cli, PI_NETLOGON, global_myname(), True)) {
+ DEBUG(2,("rpc bind to %s failed\n", PIPE_NETLOGON));
+ cli_close(cli, cli->nt_pipe_fnum);
+ return False;
+ }
+
return True;
}
+
+const char *cli_pipe_get_name(struct cli_state *cli)
+{
+ return cli->pipe_name;
+}
+
+
/****************************************************************************
close the session
****************************************************************************/
void cli_nt_session_close(struct cli_state *cli)
{
+ if (cli->saved_netlogon_pipe_fnum != 0) {
+ cli_close(cli, cli->saved_netlogon_pipe_fnum);
+ cli->saved_netlogon_pipe_fnum = 0;
+ }
cli_close(cli, cli->nt_pipe_fnum);
cli->nt_pipe_fnum = 0;
}