Allow multiple fragment RPC's to be sent.
authorJim McDonough <jmcd@samba.org>
Thu, 7 Nov 2002 14:40:25 +0000 (14:40 +0000)
committerJim McDonough <jmcd@samba.org>
Thu, 7 Nov 2002 14:40:25 +0000 (14:40 +0000)
(This used to be commit d423e6424bc3c61281ad30cd1c66540b522b5d3e)

source3/rpc_client/cli_pipe.c

index 995697d885906416646a94f9b43df92b8ab48893..adfdfe986e5e6aba0500303f02221b9d2b78cee4 100644 (file)
@@ -323,7 +323,7 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata, int len, int
 
  ****************************************************************************/
 
-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;
@@ -337,14 +337,14 @@ static BOOL rpc_api_pipe(struct cli_state *cli, uint16 cmd, prs_struct *data, pr
        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] = 0x26
        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
@@ -354,7 +354,7 @@ static BOOL rpc_api_pipe(struct cli_state *cli, uint16 cmd, prs_struct *data, pr
        if (!cli_api_pipe(cli, "\\PIPE\\",
                  setup, 2, 0,                     /* Setup, length, max */
                  NULL, 0, 0,                      /* Params, length, max */
-                 pdata, data_len, 1024,           /* data, length, max */                  
+                 pdata, data_len, max_data,       /* data, length, max */
                  &rparam, &rparam_len,            /* return params, len */
                  &prdata, &rdata_len))            /* return data, len */
        {
@@ -367,8 +367,8 @@ static BOOL rpc_api_pipe(struct cli_state *cli, uint16 cmd, prs_struct *data, pr
        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;
        }
 
@@ -730,17 +730,18 @@ static BOOL create_rpc_bind_resp(struct pwd_info *pwd,
  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 
@@ -748,9 +749,9 @@ static BOOL create_rpc_request(prs_struct *rpc_out, uint8 op_num, int data_len,
         */
 
        if (auth_len != 0)
-               alloc_hint = data_len - RPC_HEADER_LEN - RPC_HDR_AUTH_LEN - auth_len;
+               alloc_hint = data_left - RPC_HEADER_LEN - RPC_HDR_AUTH_LEN - auth_len;
        else
-               alloc_hint = data_len - RPC_HEADER_LEN;
+               alloc_hint = data_left - RPC_HEADER_LEN;
 
        DEBUG(10,("create_rpc_request: data_len: %x auth_len: %x alloc_hint: %x\n",
                   data_len, auth_len, alloc_hint));
@@ -760,17 +761,172 @@ static BOOL create_rpc_request(prs_struct *rpc_out, uint8 op_num, int data_len,
 
        /* 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;
+}
+
+static BOOL create_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;
+}
 
+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;
 }
 
+BOOL rpc_api_pipe_req(struct cli_state *cli, uint8 op_num,
+                      prs_struct *data, prs_struct *rdata)
+{
+       uint32 auth_len, max_data, data_left, data_sent;
+       BOOL ret = False;
+       BOOL auth_verify, auth_seal;
+       fstring dump_name;
+
+       auth_verify = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SIGN) != 0);
+       auth_seal   = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SEAL) != 0);
+
+       auth_len = (auth_verify ? RPC_AUTH_NTLMSSP_CHK_LEN : 0);
+
+       /*
+        * 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;
+
+       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 callid;
+
+               /*
+                * how much will we send this time
+                */
+               send_size = MIN(data_left, max_data);
+               data_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN + send_size +
+                       (auth_verify ? RPC_HDR_AUTH_LEN : 0) + auth_len;
+
+               /*
+                * 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;
+               }
+
+               if (data_left == prs_offset(data)) {
+                       flags |= RPC_FLG_FIRST;
+                       callid = 0;
+               }
+               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;
+               }
+
+               /*
+                * 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);
+               }
+
+               /*
+                * Now copy the data into the outgoing packet.
+                */
+               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_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;
+                       }
+               }
+
+               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;
+}
 
 /**
  * Send a request on an RPC pipe and get a response.
@@ -779,7 +935,7 @@ static BOOL create_rpc_request(prs_struct *rpc_out, uint8 op_num, int data_len,
  * @param rdata Unparsed NDR response data.
 **/
 
-BOOL rpc_api_pipe_req(struct cli_state *cli, uint8 op_num,
+BOOL rpc_api_pipe_req2(struct cli_state *cli, uint8 op_num,
                       prs_struct *data, prs_struct *rdata)
 {
        prs_struct outgoing_packet;
@@ -836,7 +992,8 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, uint8 op_num,
         * Write out the RPC header and the request header.
         */
 
-       if(!create_rpc_request(&outgoing_packet, op_num, data_len, auth_len)) {
+       if(!create_rpc_request(&outgoing_packet, op_num, data_len, auth_len,
+                              (uint8) RPC_FLG_FIRST | RPC_FLG_LAST, 0, data_len)) {
                DEBUG(0,("rpc_api_pipe_req: Failed to create RPC request.\n"));
                prs_mem_free(&outgoing_packet);
                return False;
@@ -896,7 +1053,7 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, uint8 op_num,
 
        DEBUG(100,("data_len: %x data_calc_len: %x\n", data_len, prs_offset(&outgoing_packet)));
 
-       ret = rpc_api_pipe(cli, 0x0026, &outgoing_packet, rdata);
+       ret = rpc_api_pipe(cli, &outgoing_packet, rdata);
 
        /* Also capture received data */
        slprintf(dump_name, sizeof(dump_name) - 1, "reply_%s",
@@ -1196,7 +1353,7 @@ BOOL rpc_pipe_bind(struct cli_state *cli, const int pipe_idx, char *my_name)
        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"));