This is the netlogon schannel client code. Try a
[sfrench/samba-autobuild/.git] / source3 / rpc_client / cli_pipe.c
index 61c6f2889ff3b2c6a0abfe7daa9e481c7b95c235..c4a9b37127e1e530e45101c8746ae9d11a6b6343 100644 (file)
@@ -27,8 +27,6 @@
 #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.
@@ -193,6 +191,7 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata, int len, int
 
        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)));
@@ -295,12 +294,54 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata, int len, int
                }
                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 auth len %d\n", auth_len));
+                       return False;
+               }
+
+               if (dp - prs_data_p(rdata) > prs_data_size(rdata)) {
+                       DEBUG(0,("rpc_auth_pipe: auth data > data size !\n"));
+                       return False;
+               }
+
+               DEBUG(10,("rpc_auth_pipe: 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("auth_sign", &chk, &auth_verf, 0)) {
+                       DEBUG(0, ("rpc_auth_pipe: unmarshalling "
+                                 "RPC_AUTH_NETSECK_CHK failed\n"));
+                       return False;
+               }
+
+               if (!netsec_decode(&cli->auth_info, &chk, reply_data, data_len)) {
+                       DEBUG(0, ("rpc_auth_pipe: Could not decode schannel\n"));
+                       return False;
+               }
+               cli->auth_info.seq_num++;
+       }
        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
@@ -323,7 +364,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 +378,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] = 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
@@ -354,7 +395,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 +408,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;
        }
 
@@ -544,9 +585,9 @@ static BOOL rpc_api_pipe(struct cli_state *cli, uint16 cmd, prs_struct *data, pr
 
  ********************************************************************/
 
-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;
@@ -598,6 +639,43 @@ static BOOL create_rpc_bind_req(prs_struct *rpc_out, BOOL do_auth, uint32 rpc_ca
                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, my_name, domain);
+
+               /*
+                * 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, 0x3, rpc_call_id, 
                RPC_HEADER_LEN + RPC_HDR_RB_LEN + prs_offset(&auth_info),
@@ -640,7 +718,7 @@ static BOOL create_rpc_bind_req(prs_struct *rpc_out, BOOL do_auth, uint32 rpc_ca
  ********************************************************************/
 
 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)
@@ -730,17 +808,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 
@@ -760,17 +839,77 @@ 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;
+}
+
+/*******************************************************************
+ 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.
+ ********************************************************************/
+
+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.
@@ -782,129 +921,204 @@ static BOOL create_rpc_request(prs_struct *rpc_out, uint8 op_num, int data_len,
 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;
        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);
 
-       /* Optionally capture for use in debugging */
-       slprintf(dump_name, sizeof(dump_name) - 1, "call_%s",
-                cli_pipe_get_name(cli));
-       prs_dump_before(dump_name, op_num, data);
+       auth_len = 0;
 
-       /*
-        * The auth_len doesn't include the RPC_HDR_AUTH_LEN.
-        */
+       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;
+
+       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 = 0;
+               uint32 auth_padding = 0;
+               RPC_AUTH_NETSEC_CHK verf;
 
-       if((prs_offset(data) % 8) != 0) {
-               DEBUG(5,("rpc_api_pipe_req: Outgoing data not a multiple of 8 bytes....\n"));
-       }
+               /*
+                * how much will we send this time
+                */
+               send_size = MIN(data_left, max_data);
 
-       data_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN + prs_offset(data) +
-                       (auth_verify ? RPC_HDR_AUTH_LEN : 0) + auth_len;
+               /*
+                * 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.
+                */
 
-       /*
-        * Malloc a parse struct to hold it (and enough for alignments).
-        */
+               if (auth_schannel)
+                       auth_padding = 8 - (send_size & 7);
 
-       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;
-       }
+               data_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN + send_size +
+                       ((auth_verify|auth_schannel) ? RPC_HDR_AUTH_LEN : 0) +
+                       auth_len + auth_padding;
 
-       pdata_out = prs_data_p(&outgoing_packet);
-       
-       /*
-        * Write out the RPC header and the request header.
-        */
+               /*
+                * 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(!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;
-       }
+               if (data_left == prs_offset(data))
+                       flags |= RPC_FLG_FIRST;
 
-       /*
-        * Seal the outgoing data if requested.
-        */
+               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;
+               }
 
-       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));
-       }
+               /*
+                * 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.
-        */
+               /*
+                * Now copy the data into the outgoing packet.
+                */
 
-       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;
-       }
+               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];
+                       BOOL ret;
+                       int i;
+                       prs_struct netsec_blob;
+
+                       memset(sign, 0, sizeof(sign));
+                       sign[4] = 0x80;
+
+                       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;
+                       }
 
-       /*
-        * Add a trailing auth_verifier if needed.
-        */
+                       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;
+                       }
 
-       if (auth_seal || auth_verify) {
-               RPC_HDR_AUTH hdr_auth;
+                       netsec_blob.align = 8;
 
-               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;
+                       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);
+               } 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;
+                       }
                }
-       }
-
-       /*
-        * Finally the auth data itself.
-        */
 
-       if (auth_verify) {
-               RPC_AUTH_NTLMSSP_CHK chk;
-               uint32 current_offset = prs_offset(&outgoing_packet);
+               /*
+                * 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;
+                       }
+               }
 
-               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;
+               /*
+                * 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;
+                       }
+               }
+
+               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);
 
-       prs_mem_free(&outgoing_packet);
-
        return ret;
 }
 
@@ -974,7 +1188,7 @@ int get_pipe_index( const char *pipe_name )
  check the rpc bind acknowledge response
 ****************************************************************************/
 
-char* get_pipe_name_from_index( const int pipe_index )
+const char* get_pipe_name_from_index( const int pipe_index )
 {
 
        if ( (pipe_index < 0) || (pipe_index >= PI_MAX_PIPES) )
@@ -1054,7 +1268,7 @@ static BOOL check_bind_response(RPC_HDR_BA *hdr_ba, const int pipe_idx, RPC_IFAC
        /* 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;
        }
 
@@ -1107,7 +1321,7 @@ static BOOL rpc_send_auth_reply(struct cli_state *cli, prs_struct *rdata, uint32
        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);
                                            
@@ -1159,7 +1373,8 @@ static BOOL rpc_send_auth_reply(struct cli_state *cli, prs_struct *rdata, uint32
  Do an rpc bind.
 ****************************************************************************/
 
-BOOL rpc_pipe_bind(struct cli_state *cli, const int pipe_idx, 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;
@@ -1188,15 +1403,15 @@ BOOL rpc_pipe_bind(struct cli_state *cli, const int pipe_idx, char *my_name)
        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"));
@@ -1208,7 +1423,7 @@ BOOL rpc_pipe_bind(struct cli_state *cli, const int pipe_idx, char *my_name)
                }
 
                if(!check_bind_response(&hdr_ba, pipe_idx, &transfer)) {
-                       DEBUG(0,("rpc_pipe_bind: check_bind_response failed.\n"));
+                       DEBUG(2,("rpc_pipe_bind: check_bind_response failed.\n"));
                        prs_mem_free(&rdata);
                        return False;
                }
@@ -1233,16 +1448,6 @@ BOOL rpc_pipe_bind(struct cli_state *cli, const int pipe_idx, char *my_name)
        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.
  ****************************************************************************/
@@ -1251,6 +1456,9 @@ 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 */
@@ -1285,9 +1493,9 @@ BOOL cli_nt_session_open(struct cli_state *cli, const int pipe_idx)
 
        /******************* bind request on pipe *****************/
 
-       if (!rpc_pipe_bind(cli, pipe_idx, 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;
        }
@@ -1301,10 +1509,10 @@ BOOL cli_nt_session_open(struct cli_state *cli, const int pipe_idx)
        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);
 
@@ -1315,6 +1523,106 @@ BOOL cli_nt_session_open(struct cli_state *cli, const int pipe_idx)
 }
 
 
+/****************************************************************************
+ 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) {
+
+               /* If we open \\PIPE\NETLOGON here, NT4SP6
+                  gives us an ACCESS_DENIED. Do I have to
+                  understand this?
+               */
+               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;
@@ -1327,6 +1635,10 @@ 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;
 }