This is the netlogon schannel client code. Try a
[sfrench/samba-autobuild/.git] / source3 / rpc_client / cli_pipe.c
index 7ca274efc32a83550a64100d7ba9ea2de7d05c4c..c4a9b37127e1e530e45101c8746ae9d11a6b6343 100644 (file)
@@ -1,7 +1,5 @@
-
 /* 
- *  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,
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-
-#ifdef SYSLOG
-#undef SYSLOG
-#endif
-
 #include "includes.h"
 
-extern int DEBUGLEVEL;
+#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.
@@ -55,7 +48,6 @@ static BOOL rpc_read(struct cli_state *cli, prs_struct *rdata, uint32 data_to_re
        int stream_offset = 0;
        int num_read;
        char *pdata;
-       uint32 err;
        int extra_data_size = ((int)*rdata_offset) + ((int)data_to_read) - (int)prs_data_size(rdata);
 
        DEBUG(5,("rpc_read: data_to_read: %u rdata offset: %u extra_data_size: %d\n",
@@ -77,6 +69,9 @@ static BOOL rpc_read(struct cli_state *cli, prs_struct *rdata, uint32 data_to_re
 
        do /* read data using SMBreadX */
        {
+               uint32 ecode;
+               uint8 eclass;
+
                if (size > (size_t)data_to_read)
                        size = (size_t)data_to_read;
 
@@ -85,9 +80,13 @@ static BOOL rpc_read(struct cli_state *cli, prs_struct *rdata, uint32 data_to_re
                DEBUG(5,("rpc_read: num_read = %d, read offset: %d, to read: %d\n",
                          num_read, stream_offset, data_to_read));
 
-               if (cli_error(cli, NULL, &err, NULL)) {
-                       DEBUG(0,("rpc_read: Error %u in cli_read\n", (unsigned int)err ));
-                       return False;
+               if (cli_is_dos_error(cli)) {
+                        cli_dos_error(cli, &eclass, &ecode);
+                        if (eclass != ERRDOS && ecode != ERRmoredata) {
+                                DEBUG(0,("rpc_read: Error %d/%u in cli_read\n",
+                                         eclass, (unsigned int)ecode));
+                                return False;
+                        }
                }
 
                data_to_read -= num_read;
@@ -106,7 +105,7 @@ static BOOL rpc_read(struct cli_state *cli, prs_struct *rdata, uint32 data_to_re
 }
 
 /****************************************************************************
- Checks the header.
+ Checks the header. This will set the endian bit in the rdata prs_struct. JRA.
  ****************************************************************************/
 
 static BOOL rpc_check_hdr(prs_struct *rdata, RPC_HDR *rhdr, 
@@ -114,6 +113,8 @@ static BOOL rpc_check_hdr(prs_struct *rdata, RPC_HDR *rhdr,
 {
        DEBUG(5,("rpc_check_hdr: rdata->data_size = %u\n", (uint32)prs_data_size(rdata) ));
 
+       /* Next call sets endian bit. */
+
        if(!smb_io_rpc_hdr("rpc_hdr   ", rhdr, rdata, 0)) {
                DEBUG(0,("rpc_check_hdr: Failed to unmarshall RPC_HDR.\n"));
                return False;
@@ -190,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)));
@@ -223,7 +225,12 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata, int len, int
 
                memcpy(data, dp, sizeof(data));
                
-               prs_init(&auth_req , 0, 4, cli->mem_ctx, UNMARSHALL);
+               prs_init(&auth_req , 0, cli->mem_ctx, UNMARSHALL);
+
+               /* The endianness must be preserved... JRA. */
+
+               prs_set_endian_data(&auth_req, rdata->bigendian_data);
+
                prs_give_memory(&auth_req, data, RPC_HDR_AUTH_LEN, False);
 
                /*
@@ -267,7 +274,11 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata, int len, int
                memcpy(data, dp, RPC_AUTH_NTLMSSP_CHK_LEN);
                dump_data(100, data, auth_len);
 
-               prs_init(&auth_verf, 0, 4, cli->mem_ctx, UNMARSHALL);
+               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_NTLMSSP_CHK_LEN, False);
 
                if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &chk, &auth_verf, 0)) {
@@ -283,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
@@ -311,13 +364,12 @@ 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;
        uint32 rparam_len = 0;
        uint16 setup[2];
-       uint32 err;
        BOOL first = True;
        BOOL last  = True;
        RPC_HDR rhdr;
@@ -326,20 +378,24 @@ 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; 
+       /* Create setup parameters - must be in native byte order. */
+
+       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
+          appears in a SMBtrans request and response.  Larger RPC
+          responses are received further on. */
 
-       /* send the data: receive a response. */
-       if (!cli_api_pipe(cli, "\\PIPE\\\0\0\0", 8,
+       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 */
        {
@@ -347,28 +403,26 @@ static BOOL rpc_api_pipe(struct cli_state *cli, uint16 cmd, prs_struct *data, pr
                return False;
        }
 
-       /*
-        * Throw away returned params - we know we won't use them.
-        */
+       /* Throw away returned params - we know we won't use them. */
 
-       if(rparam) {
-               free(rparam);
-               rparam = NULL;
-       }
+       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;
        }
 
        /*
-        * Give this memory as dynamically allocated to the return parse struct.
+        * Give this memory as dynamically allocated to the return parse
+        * struct.  
         */
 
        prs_give_memory(rdata, prdata, rdata_len, True);
        current_offset = rdata_len;
 
+       /* This next call sets the endian bit correctly in rdata. */
+
        if (!rpc_check_hdr(rdata, &rhdr, &first, &last, &len)) {
                prs_mem_free(rdata);
                return False;
@@ -394,13 +448,15 @@ static BOOL rpc_api_pipe(struct cli_state *cli, uint16 cmd, prs_struct *data, pr
        DEBUG(5,("rpc_api_pipe: len left: %u smbtrans read: %u\n",
                  (unsigned int)len, (unsigned int)rdata_len ));
 
-       /* check if data to be sent back was too large for one SMB. */
-       /* err status is only informational: the _real_ check is on the length */
+       /* check if data to be sent back was too large for one SMBtrans */
+       /* err status is only informational: the _real_ check is on the
+           length */
+
        if (len > 0) { 
                /* || err == (0x80000000 | STATUS_BUFFER_OVERFLOW)) */
-               /*
-                * Read the rest of the first response PDU.
-                */
+
+               /* Read the remaining part of the first response fragment */
+
                if (!rpc_read(cli, rdata, len, &current_offset)) {
                        prs_mem_free(rdata);
                        return False;
@@ -433,7 +489,8 @@ static BOOL rpc_api_pipe(struct cli_state *cli, uint16 cmd, prs_struct *data, pr
        }
 
        /*
-        * Read more fragments until we get the last one.
+        * Read more fragments using SMBreadX until we get one with the
+        * last bit set.
         */
 
        while (!last) {
@@ -441,18 +498,23 @@ static BOOL rpc_api_pipe(struct cli_state *cli, uint16 cmd, prs_struct *data, pr
                int num_read;
                char hdr_data[RPC_HEADER_LEN+RPC_HDR_RESP_LEN];
                prs_struct hps;
+               uint8 eclass;
+               uint32 ecode;
 
                /*
                 * First read the header of the next PDU.
                 */
 
-               prs_init(&hps, 0, 4, cli->mem_ctx, UNMARSHALL);
+               prs_init(&hps, 0, cli->mem_ctx, UNMARSHALL);
                prs_give_memory(&hps, hdr_data, sizeof(hdr_data), False);
 
                num_read = cli_read(cli, cli->nt_pipe_fnum, hdr_data, 0, RPC_HEADER_LEN+RPC_HDR_RESP_LEN);
-               if (cli_error(cli, NULL, &err, NULL)) {
-                       DEBUG(0,("rpc_api_pipe: cli_read error : %d\n", err ));
-                       return False;
+               if (cli_is_dos_error(cli)) {
+                        cli_dos_error(cli, &eclass, &ecode);
+                        if (eclass != ERRDOS && ecode != ERRmoredata) {
+                                DEBUG(0,("rpc_api_pipe: cli_read error : %d/%d\n", eclass, ecode));
+                                return False;
+                        }
                }
 
                DEBUG(5,("rpc_api_pipe: read header (size:%d)\n", num_read));
@@ -463,9 +525,20 @@ static BOOL rpc_api_pipe(struct cli_state *cli, uint16 cmd, prs_struct *data, pr
                        return False;
                }
 
+               /* This call sets the endianness in hps. */
+
                if (!rpc_check_hdr(&hps, &rhdr, &first, &last, &len))
                        return False;
 
+               /* Ensure the endianness in rdata is set correctly - must be same as hps. */
+
+               if (hps.bigendian_data != rdata->bigendian_data) {
+                       DEBUG(0,("rpc_api_pipe: Error : Endianness changed from %s to %s\n",
+                               rdata->bigendian_data ? "big" : "little",
+                               hps.bigendian_data ? "big" : "little" ));
+                       return False;
+               }
+
                if(!smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, &hps, 0)) {
                        DEBUG(0,("rpc_api_pipe: Error in unmarshalling RPC_HDR_RESP.\n"));
                        return False;
@@ -512,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;
@@ -522,7 +595,7 @@ static BOOL create_rpc_bind_req(prs_struct *rpc_out, BOOL do_auth, uint32 rpc_ca
        prs_struct auth_info;
        int auth_len = 0;
 
-       prs_init(&auth_info, 0, 4, prs_get_mem_context(rpc_out), MARSHALL);
+       prs_init(&auth_info, 0, prs_get_mem_context(rpc_out), MARSHALL);
 
        if (do_auth) {
                RPC_HDR_AUTH hdr_auth;
@@ -566,8 +639,45 @@ 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, 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);
 
@@ -608,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)
@@ -626,7 +736,7 @@ static BOOL create_rpc_bind_resp(struct pwd_info *pwd,
         * Marshall the variable length data into a temporary parse
         * struct, pointing into a 4k local buffer.
         */
-        prs_init(&auth_info, 0, 4, prs_get_mem_context(rpc_out), MARSHALL);
+       prs_init(&auth_info, 0, prs_get_mem_context(rpc_out), MARSHALL);
 
        /*
         * Use the 4k buffer to store the auth info.
@@ -698,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 
@@ -728,136 +839,285 @@ 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.
+ ********************************************************************/
 
-/****************************************************************************
- 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;
+       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;
 
-       auth_len = (auth_verify ? RPC_AUTH_NTLMSSP_CHK_LEN : 0);
+       if (auth_verify)
+               auth_len = RPC_AUTH_NTLMSSP_CHK_LEN;
+
+       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, 4, 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;
+                       }
 
-       /*
-        * Finally the auth data itself.
-        */
+                       init_rpc_auth_netsec_chk(&verf, netsec_sig, nullbytes,
+                                                sign, nullbytes);
 
-       if (auth_verify) {
-               RPC_AUTH_NTLMSSP_CHK chk;
-               uint32 current_offset = prs_offset(&outgoing_packet);
+                       netsec_encode(&(cli->auth_info), &verf,
+                                     prs_data_p(&netsec_blob),
+                                     prs_data_size(&netsec_blob));
 
-               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;
+                       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;
+                       }
+               }
+
+               /*
+                * 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;
 }
@@ -866,7 +1126,7 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, uint8 op_num,
  Set the handle state.
 ****************************************************************************/
 
-static BOOL rpc_pipe_set_hnd_state(struct cli_state *cli, char *pipe_name, uint16 device_state)
+static BOOL rpc_pipe_set_hnd_state(struct cli_state *cli, const char *pipe_name, uint16 device_state)
 {
        BOOL state_set = False;
        char param[2];
@@ -889,7 +1149,7 @@ static BOOL rpc_pipe_set_hnd_state(struct cli_state *cli, char *pipe_name, uint1
        setup[1] = cli->nt_pipe_fnum; /* pipe file handle.  got this from an SMBOpenX. */
 
        /* send the data on \PIPE\ */
-       if (cli_api_pipe(cli, "\\PIPE\\\0\0\0", 8,
+       if (cli_api_pipe(cli, "\\PIPE\\",
                    setup, 2, 0,                /* setup, length, max */
                    param, 2, 0,                /* param, length, max */
                    NULL, 0, 1024,              /* data, length, max */
@@ -900,10 +1160,8 @@ static BOOL rpc_pipe_set_hnd_state(struct cli_state *cli, char *pipe_name, uint1
                state_set = True;
        }
 
-       if (rparam)
-               free(rparam);
-       if (rdata)
-               free(rdata );
+       SAFE_FREE(rparam);
+       SAFE_FREE(rdata);
 
        return state_set;
 }
@@ -912,29 +1170,46 @@ static BOOL rpc_pipe_set_hnd_state(struct cli_state *cli, char *pipe_name, uint1
  check the rpc bind acknowledge response
 ****************************************************************************/
 
-static BOOL valid_pipe_name(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;
 }
 
@@ -942,31 +1217,50 @@ static BOOL valid_pipe_name(char *pipe_name, RPC_IFACE *abstract, RPC_IFACE *tra
  check the rpc bind acknowledge response
 ****************************************************************************/
 
-static BOOL check_bind_response(RPC_HDR_BA *hdr_ba, 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) {
-               DEBUG(6,("bind_rpc_pipe: searching pipe name: client:%s server:%s\n",
-               pipe_names[i].client_pipe , pipe_names[i].server_pipe ));
-
-               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;
        }
@@ -974,7 +1268,7 @@ static BOOL check_bind_response(RPC_HDR_BA *hdr_ba, char *pipe_name, RPC_IFACE *
        /* 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;
        }
 
@@ -1022,12 +1316,12 @@ static BOOL rpc_send_auth_reply(struct cli_state *cli, prs_struct *rdata, uint32
 
        pwd_make_lm_nt_owf(&cli->pwd, rhdr_chal.challenge);
 
-       prs_init(&rpc_out, 0, 4, cli->mem_ctx, MARSHALL);
+       prs_init(&rpc_out, 0, cli->mem_ctx, MARSHALL);
 
        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);
                                            
@@ -1079,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, 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;
@@ -1089,12 +1384,15 @@ BOOL rpc_pipe_bind(struct cli_state *cli, char *pipe_name, char *my_name)
        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;
+
+       DEBUG(5,("Bind RPC Pipe[%x]: %s\n", cli->nt_pipe_fnum, pipe_names[pipe_idx].client_pipe));
 
-       if (!valid_pipe_name(pipe_name, &abstract, &transfer))
+       if (!valid_pipe_name(pipe_idx, &abstract, &transfer))
                return False;
 
-       prs_init(&rpc_out, 0, 4, cli->mem_ctx, MARSHALL);
+       prs_init(&rpc_out, 0, cli->mem_ctx, MARSHALL);
 
        /*
         * Use the MAX_PDU_FRAG_LEN buffer to store the bind request.
@@ -1105,15 +1403,15 @@ BOOL rpc_pipe_bind(struct cli_state *cli, char *pipe_name, 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, 4, cli->mem_ctx, UNMARSHALL);
+       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"));
@@ -1124,8 +1422,8 @@ BOOL rpc_pipe_bind(struct cli_state *cli, char *pipe_name, char *my_name)
                        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;
                }
@@ -1151,42 +1449,41 @@ BOOL rpc_pipe_bind(struct cli_state *cli, char *pipe_name, char *my_name)
 }
 
 /****************************************************************************
Set ntlmssp negotiation flags.
Open a session.
  ****************************************************************************/
 
-void cli_nt_set_ntlmssp_flgs(struct cli_state *cli, uint32 ntlmssp_flgs)
+BOOL cli_nt_session_open(struct cli_state *cli, const int pipe_idx)
 {
-       cli->ntlmssp_cli_flgs = ntlmssp_flgs;
-}
+       int fnum;
 
+       /* At the moment we can't have more than one pipe open over
+           a cli connection. )-: */
 
-/****************************************************************************
- Open a session.
****************************************************************************/
+       SMB_ASSERT(cli->nt_pipe_fnum == 0);
+       
      /* The pipe index must fall within our array */
 
-BOOL cli_nt_session_open(struct cli_state *cli, char *pipe_name)
-{
-       int fnum;
+       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);
@@ -1196,9 +1493,9 @@ BOOL cli_nt_session_open(struct cli_state *cli, char *pipe_name)
 
        /******************* 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;
        }
@@ -1212,21 +1509,136 @@ BOOL cli_nt_session_open(struct cli_state *cli, char *pipe_name)
        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) {
+
+               /* 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;
+}
+
+
 /****************************************************************************
 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;
 }