Replace cli_rpc_pipe_close by a talloc destructor on rpc_pipe_struct
[kai/samba.git] / source3 / rpc_client / cli_pipe.c
index 0a2e66448950510f101e6ce189dee030e6832aeb..b0d6f8eafd6c5f6fe05bd9db264b29d1be440c39 100644 (file)
@@ -5,7 +5,7 @@
  *  
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
+ *  the Free Software Foundation; either version 3 of the License, or
  *  (at your option) any later version.
  *  
  *  This program is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@
  *  GNU General Public License for more details.
  *  
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "includes.h"
@@ -250,7 +249,7 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, RPC_HDR *pr
        data = (unsigned char *)(prs_data_p(current_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN);
        data_len = (size_t)(prhdr->frag_len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN - RPC_HDR_AUTH_LEN - auth_len);
 
-       full_packet_data = prs_data_p(current_pdu);
+       full_packet_data = (unsigned char *)prs_data_p(current_pdu);
        full_packet_data_len = prhdr->frag_len - auth_len;
 
        /* Pull the auth header and the following data into a blob. */
@@ -265,7 +264,7 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, RPC_HDR *pr
                return NT_STATUS_BUFFER_TOO_SMALL;
        }
 
-       auth_blob.data = prs_data_p(current_pdu) + prs_offset(current_pdu);
+       auth_blob.data = (unsigned char *)prs_data_p(current_pdu) + prs_offset(current_pdu);
        auth_blob.length = auth_len;
 
        switch (cli->auth.auth_level) {
@@ -280,7 +279,7 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, RPC_HDR *pr
                                DEBUG(0,("cli_pipe_verify_ntlmssp: failed to unseal "
                                        "packet from remote machine %s on pipe %s "
                                        "fnum 0x%x. Error was %s.\n",
-                                       cli->cli->desthost,
+                                       cli->desthost,
                                        cli->pipe_name,
                                        (unsigned int)cli->fnum,
                                        nt_errstr(status) ));
@@ -298,7 +297,7 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, RPC_HDR *pr
                                DEBUG(0,("cli_pipe_verify_ntlmssp: check signing failed on "
                                        "packet from remote machine %s on pipe %s "
                                        "fnum 0x%x. Error was %s.\n",
-                                       cli->cli->desthost,
+                                       cli->desthost,
                                        cli->pipe_name,
                                        (unsigned int)cli->fnum,
                                        nt_errstr(status) ));
@@ -401,7 +400,7 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *p
                DEBUG(3,("cli_pipe_verify_schannel: failed to decode PDU "
                                "Connection to remote machine %s "
                                "pipe %s fnum 0x%x.\n",
-                               cli->cli->desthost,
+                               cli->desthost,
                                cli->pipe_name,
                                (unsigned int)cli->fnum ));
                return NT_STATUS_INVALID_PARAMETER;
@@ -462,7 +461,7 @@ static NTSTATUS cli_pipe_validate_rpc_response(struct rpc_pipe_client *cli, RPC_
                        if (prhdr->auth_len) {
                                DEBUG(3, ("cli_pipe_validate_rpc_response: Connection to remote machine %s "
                                        "pipe %s fnum 0x%x - got non-zero auth len %u.\n",
-                                       cli->cli->desthost,
+                                       cli->desthost,
                                        cli->pipe_name,
                                        (unsigned int)cli->fnum,
                                        (unsigned int)prhdr->auth_len ));
@@ -490,7 +489,7 @@ static NTSTATUS cli_pipe_validate_rpc_response(struct rpc_pipe_client *cli, RPC_
                default:
                        DEBUG(3, ("cli_pipe_validate_rpc_response: Connection to remote machine %s "
                                "pipe %s fnum %x - unknown internal auth type %u.\n",
-                               cli->cli->desthost,
+                               cli->desthost,
                                cli->pipe_name,
                                (unsigned int)cli->fnum,
                                cli->auth.auth_type ));
@@ -596,7 +595,7 @@ static NTSTATUS cli_pipe_validate_current_pdu(struct rpc_pipe_client *cli, RPC_H
                case RPC_BINDNACK:
                        DEBUG(1, ("cli_pipe_validate_current_pdu: Bind NACK received from remote machine %s "
                                "pipe %s fnum 0x%x!\n",
-                               cli->cli->desthost,
+                               cli->desthost,
                                cli->pipe_name,
                                (unsigned int)cli->fnum));
                        /* Use this for now... */
@@ -619,8 +618,8 @@ static NTSTATUS cli_pipe_validate_current_pdu(struct rpc_pipe_client *cli, RPC_H
 
                        DEBUG(1, ("cli_pipe_validate_current_pdu: RPC fault code %s received from remote machine %s "
                                "pipe %s fnum 0x%x!\n",
-                               nt_errstr(fault_resp.status),
-                               cli->cli->desthost,
+                               dcerpc_errstr(NT_STATUS_V(fault_resp.status)),
+                               cli->desthost,
                                cli->pipe_name,
                                (unsigned int)cli->fnum));
                        if (NT_STATUS_IS_OK(fault_resp.status)) {
@@ -635,7 +634,7 @@ static NTSTATUS cli_pipe_validate_current_pdu(struct rpc_pipe_client *cli, RPC_H
                        DEBUG(0, ("cli_pipe_validate_current_pdu: unknown packet type %u received "
                                "from remote machine %s pipe %s fnum 0x%x!\n",
                                (unsigned int)prhdr->pkt_type,
-                               cli->cli->desthost,
+                               cli->desthost,
                                cli->pipe_name,
                                (unsigned int)cli->fnum));
                        return NT_STATUS_INVALID_INFO_CLASS;
@@ -645,7 +644,7 @@ static NTSTATUS cli_pipe_validate_current_pdu(struct rpc_pipe_client *cli, RPC_H
                DEBUG(3, ("cli_pipe_validate_current_pdu: Connection to remote machine %s "
                        "pipe %s fnum %x got an unexpected RPC packet "
                        "type - %u, not %u\n",
-                       cli->cli->desthost,
+                       cli->desthost,
                        cli->pipe_name,
                        (unsigned int)cli->fnum,
                        prhdr->pkt_type,
@@ -684,7 +683,7 @@ static NTSTATUS cli_pipe_reset_current_pdu(struct rpc_pipe_client *cli, RPC_HDR
        /* Common case. */
        if (current_pdu_len == (uint32)prhdr->frag_len) {
                prs_mem_free(current_pdu);
-               prs_init(current_pdu, 0, prs_get_mem_context(current_pdu), UNMARSHALL);
+               prs_init_empty(current_pdu, prs_get_mem_context(current_pdu), UNMARSHALL);
                /* Make current_pdu dynamic with no memory. */
                prs_give_memory(current_pdu, 0, 0, True);
                return NT_STATUS_OK;
@@ -744,8 +743,8 @@ static NTSTATUS rpc_api_pipe(struct rpc_pipe_client *cli,
        char *rparam = NULL;
        uint32 rparam_len = 0;
        uint16 setup[2];
-       char *pdata = data ? prs_data_p(data) : NULL;
-       uint32 data_len = data ? prs_offset(data) : 0;
+       char *pdata = prs_data_p(data);
+       uint32 data_len = prs_offset(data);
        char *prdata = NULL;
        uint32 rdata_len = 0;
        uint32 max_data = cli->max_xmit_frag ? cli->max_xmit_frag : RPC_MAX_PDU_FRAG_LEN;
@@ -758,14 +757,14 @@ static NTSTATUS rpc_api_pipe(struct rpc_pipe_client *cli,
 #endif
 
        /* Set up the current pdu parse struct. */
-       prs_init(&current_pdu, 0, prs_get_mem_context(rbuf), UNMARSHALL);
+       prs_init_empty(&current_pdu, prs_get_mem_context(rbuf), UNMARSHALL);
 
        /* Create setup parameters - must be in native byte order. */
        setup[0] = TRANSACT_DCERPCCMD; 
        setup[1] = cli->fnum; /* Pipe file handle. */
 
        DEBUG(5,("rpc_api_pipe: Remote machine %s pipe %s fnum 0x%x\n",
-               cli->cli->desthost,
+               cli->desthost,
                cli->pipe_name,
                (unsigned int)cli->fnum ));
 
@@ -782,13 +781,15 @@ static NTSTATUS rpc_api_pipe(struct rpc_pipe_client *cli,
                  &rparam, &rparam_len,            /* return params, len */
                  &prdata, &rdata_len))            /* return data, len */
        {
-               DEBUG(0, ("rpc_api_pipe: Remote machine %s pipe %s fnum 0x%x"
+               DEBUG(0, ("rpc_api_pipe: Remote machine %s pipe %s fnum 0x%x "
                        "returned critical error. Error was %s\n",
-                       cli->cli->desthost,
+                       cli->desthost,
                        cli->pipe_name,
                        (unsigned int)cli->fnum,
                        cli_errstr(cli->cli)));
                ret = cli_get_nt_error(cli->cli);
+               SAFE_FREE(rparam);
+               SAFE_FREE(prdata);
                goto err;
        }
 
@@ -799,7 +800,7 @@ static NTSTATUS rpc_api_pipe(struct rpc_pipe_client *cli,
        if (prdata == NULL) {
                DEBUG(3,("rpc_api_pipe: Remote machine %s pipe %s "
                        "fnum 0x%x failed to return data.\n",
-                       cli->cli->desthost,
+                       cli->desthost,
                        cli->pipe_name,
                        (unsigned int)cli->fnum));
                /* Yes - some calls can truely return no data... */
@@ -849,7 +850,7 @@ static NTSTATUS rpc_api_pipe(struct rpc_pipe_client *cli,
                                /* Set the data type correctly for big-endian data on the first packet. */
                                DEBUG(10,("rpc_api_pipe: On machine %s pipe %s fnum 0x%x "
                                        "PDU data format is big-endian.\n",
-                                       cli->cli->desthost,
+                                       cli->desthost,
                                        cli->pipe_name,
                                        (unsigned int)cli->fnum));
 
@@ -886,7 +887,7 @@ static NTSTATUS rpc_api_pipe(struct rpc_pipe_client *cli,
        }
 
        DEBUG(10,("rpc_api_pipe: Remote machine %s pipe %s fnum 0x%x returned %u bytes.\n",
-               cli->cli->desthost,
+               cli->desthost,
                cli->pipe_name,
                (unsigned int)cli->fnum,
                (unsigned int)prs_data_size(rbuf) ));
@@ -913,8 +914,8 @@ static NTSTATUS create_krb5_auth_bind_req( struct rpc_pipe_client *cli,
 #ifdef HAVE_KRB5
        int ret;
        struct kerberos_auth_struct *a = cli->auth.a_u.kerberos_auth;
-       DATA_BLOB tkt = data_blob(NULL, 0);
-       DATA_BLOB tkt_wrapped = data_blob(NULL, 0);
+       DATA_BLOB tkt = data_blob_null;
+       DATA_BLOB tkt_wrapped = data_blob_null;
 
        /* We may change the pad length before marshalling. */
        init_rpc_hdr_auth(pauth_out, RPC_KRB5_AUTH_TYPE, (int)auth_level, 0, 1);
@@ -925,7 +926,7 @@ static NTSTATUS create_krb5_auth_bind_req( struct rpc_pipe_client *cli,
        /* Create the ticket for the service principal and return it in a gss-api wrapped blob. */
 
        ret = cli_krb5_get_ticket(a->service_principal, 0, &tkt,
-                       &a->session_key, (uint32)AP_OPTS_MUTUAL_REQUIRED);
+                       &a->session_key, (uint32)AP_OPTS_MUTUAL_REQUIRED, NULL, NULL);
 
        if (ret) {
                DEBUG(1,("create_krb5_auth_bind_req: cli_krb5_get_ticket for principal %s "
@@ -951,7 +952,7 @@ static NTSTATUS create_krb5_auth_bind_req( struct rpc_pipe_client *cli,
        }
 
        DEBUG(5, ("create_krb5_auth_bind_req: Created krb5 GSS blob :\n"));
-       dump_data(5, (const char *)tkt_wrapped.data, tkt_wrapped.length);
+       dump_data(5, tkt_wrapped.data, tkt_wrapped.length);
 
        data_blob_free(&tkt_wrapped);
        return NT_STATUS_OK;
@@ -970,9 +971,9 @@ static NTSTATUS create_spnego_ntlmssp_auth_rpc_bind_req( struct rpc_pipe_client
                                                prs_struct *auth_data)
 {
        NTSTATUS nt_status;
-       DATA_BLOB null_blob = data_blob(NULL, 0);
-       DATA_BLOB request = data_blob(NULL, 0);
-       DATA_BLOB spnego_msg = data_blob(NULL, 0);
+       DATA_BLOB null_blob = data_blob_null;
+       DATA_BLOB request = data_blob_null;
+       DATA_BLOB spnego_msg = data_blob_null;
 
        /* We may change the pad length before marshalling. */
        init_rpc_hdr_auth(pauth_out, RPC_SPNEGO_AUTH_TYPE, (int)auth_level, 0, 1);
@@ -1001,7 +1002,7 @@ static NTSTATUS create_spnego_ntlmssp_auth_rpc_bind_req( struct rpc_pipe_client
        }
 
        DEBUG(5, ("create_spnego_ntlmssp_auth_rpc_bind_req: NTLMSSP Negotiate:\n"));
-       dump_data(5, (const char *)spnego_msg.data, spnego_msg.length);
+       dump_data(5, spnego_msg.data, spnego_msg.length);
 
        data_blob_free(&spnego_msg);
        return NT_STATUS_OK;
@@ -1017,8 +1018,8 @@ static NTSTATUS create_ntlmssp_auth_rpc_bind_req( struct rpc_pipe_client *cli,
                                                prs_struct *auth_data)
 {
        NTSTATUS nt_status;
-       DATA_BLOB null_blob = data_blob(NULL, 0);
-       DATA_BLOB request = data_blob(NULL, 0);
+       DATA_BLOB null_blob = data_blob_null;
+       DATA_BLOB request = data_blob_null;
 
        /* We may change the pad length before marshalling. */
        init_rpc_hdr_auth(pauth_out, RPC_NTLMSSP_AUTH_TYPE, (int)auth_level, 0, 1);
@@ -1042,7 +1043,7 @@ static NTSTATUS create_ntlmssp_auth_rpc_bind_req( struct rpc_pipe_client *cli,
        }
 
        DEBUG(5, ("create_ntlmssp_auth_rpc_bind_req: NTLMSSP Negotiate:\n"));
-       dump_data(5, (const char *)request.data, request.length);
+       dump_data(5, request.data, request.length);
 
        data_blob_free(&request);
        return NT_STATUS_OK;
@@ -1065,7 +1066,10 @@ static NTSTATUS create_schannel_auth_rpc_bind_req( struct rpc_pipe_client *cli,
        /* Use lp_workgroup() if domain not specified */
 
        if (!cli->domain || !cli->domain[0]) {
-               cli->domain = lp_workgroup();
+               cli->domain = talloc_strdup(cli, lp_workgroup());
+               if (cli->domain == NULL) {
+                       return NT_STATUS_NO_MEMORY;
+               }
        }
 
        init_rpc_auth_schannel_neg(&schannel_neg, cli->domain, global_myname());
@@ -1088,11 +1092,11 @@ static NTSTATUS create_schannel_auth_rpc_bind_req( struct rpc_pipe_client *cli,
  Creates the internals of a DCE/RPC bind request or alter context PDU.
  ********************************************************************/
 
-static NTSTATUS create_bind_or_alt_ctx_internal(uint8 pkt_type,
+static NTSTATUS create_bind_or_alt_ctx_internal(enum RPC_PKT_TYPE pkt_type,
                                                prs_struct *rpc_out, 
                                                uint32 rpc_call_id,
-                                               RPC_IFACE *abstract,
-                                               RPC_IFACE *transfer,
+                                               const RPC_IFACE *abstract,
+                                               const RPC_IFACE *transfer,
                                                RPC_HDR_AUTH *phdr_auth,
                                                prs_struct *pauth_info)
 {
@@ -1143,7 +1147,7 @@ static NTSTATUS create_bind_or_alt_ctx_internal(uint8 pkt_type,
 
        if(auth_len != 0) {
                if (ss_padding_len) {
-                       unsigned char pad[8];
+                       char pad[8];
                        memset(pad, '\0', 8);
                        if (!prs_copy_data_in(rpc_out, pad, ss_padding_len)) {
                                DEBUG(0,("create_bind_or_alt_ctx_internal: failed to marshall padding.\n"));
@@ -1173,7 +1177,8 @@ static NTSTATUS create_bind_or_alt_ctx_internal(uint8 pkt_type,
 static NTSTATUS create_rpc_bind_req(struct rpc_pipe_client *cli,
                                prs_struct *rpc_out, 
                                uint32 rpc_call_id,
-                               RPC_IFACE *abstract, RPC_IFACE *transfer,
+                               const RPC_IFACE *abstract,
+                               const RPC_IFACE *transfer,
                                enum pipe_auth_type auth_type,
                                enum pipe_auth_level auth_level)
 {
@@ -1182,7 +1187,8 @@ static NTSTATUS create_rpc_bind_req(struct rpc_pipe_client *cli,
        NTSTATUS ret = NT_STATUS_OK;
 
        ZERO_STRUCT(hdr_auth);
-       prs_init(&auth_info, RPC_HDR_AUTH_LEN, prs_get_mem_context(rpc_out), MARSHALL);
+       if (!prs_init(&auth_info, RPC_HDR_AUTH_LEN, prs_get_mem_context(rpc_out), MARSHALL))
+               return NT_STATUS_NO_MEMORY;
 
        switch (auth_type) {
                case PIPE_AUTH_TYPE_SCHANNEL:
@@ -1248,7 +1254,7 @@ static NTSTATUS add_ntlmssp_auth_footer(struct rpc_pipe_client *cli,
 {
        RPC_HDR_AUTH auth_info;
        NTSTATUS status;
-       DATA_BLOB auth_blob = data_blob(NULL, 0);
+       DATA_BLOB auth_blob = data_blob_null;
        uint16 data_and_pad_len = prs_offset(outgoing_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN;
 
        if (!cli->auth.a_u.ntlmssp_state) {
@@ -1272,9 +1278,9 @@ static NTSTATUS add_ntlmssp_auth_footer(struct rpc_pipe_client *cli,
                case PIPE_AUTH_LEVEL_PRIVACY:
                        /* Data portion is encrypted. */
                        status = ntlmssp_seal_packet(cli->auth.a_u.ntlmssp_state,
-                                       prs_data_p(outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN,
+                                       (unsigned char *)prs_data_p(outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN,
                                        data_and_pad_len,
-                                       prs_data_p(outgoing_pdu),
+                                       (unsigned char *)prs_data_p(outgoing_pdu),
                                        (size_t)prs_offset(outgoing_pdu),
                                        &auth_blob);
                        if (!NT_STATUS_IS_OK(status)) {
@@ -1286,9 +1292,9 @@ static NTSTATUS add_ntlmssp_auth_footer(struct rpc_pipe_client *cli,
                case PIPE_AUTH_LEVEL_INTEGRITY:
                        /* Data is signed. */
                        status = ntlmssp_sign_packet(cli->auth.a_u.ntlmssp_state,
-                                       prs_data_p(outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN,
+                                       (unsigned char *)prs_data_p(outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN,
                                        data_and_pad_len,
-                                       prs_data_p(outgoing_pdu),
+                                       (unsigned char *)prs_data_p(outgoing_pdu),
                                        (size_t)prs_offset(outgoing_pdu),
                                        &auth_blob);
                        if (!NT_STATUS_IS_OK(status)) {
@@ -1306,7 +1312,7 @@ static NTSTATUS add_ntlmssp_auth_footer(struct rpc_pipe_client *cli,
 
        /* Finally marshall the blob. */
                                                                                                       
-       if (!prs_copy_data_in(outgoing_pdu, auth_blob.data, NTLMSSP_SIG_SIZE)) {
+       if (!prs_copy_data_in(outgoing_pdu, (const char *)auth_blob.data, NTLMSSP_SIG_SIZE)) {
                DEBUG(0,("add_ntlmssp_auth_footer: failed to add %u bytes auth blob.\n",
                        (unsigned int)NTLMSSP_SIG_SIZE));
                data_blob_free(&auth_blob);
@@ -1467,7 +1473,8 @@ NTSTATUS rpc_api_pipe_req(struct rpc_pipe_client *cli,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       prs_init(&outgoing_pdu, cli->max_xmit_frag, prs_get_mem_context(in_data), MARSHALL);
+       if (!prs_init(&outgoing_pdu, cli->max_xmit_frag, prs_get_mem_context(in_data), MARSHALL))
+               return NT_STATUS_NO_MEMORY;
 
        while (1) {
                RPC_HDR hdr;
@@ -1550,13 +1557,15 @@ NTSTATUS rpc_api_pipe_req(struct rpc_pipe_client *cli,
                        ret = rpc_api_pipe(cli, &outgoing_pdu, out_data, RPC_RESPONSE);
                        prs_mem_free(&outgoing_pdu);
 
-                       
                        if (DEBUGLEVEL >= 50) {
-                               pstring dump_name;
+                               char *dump_name = NULL;
                                /* Also capture received data */
-                               slprintf(dump_name, sizeof(dump_name) - 1, "%s/reply_%s_%d",
-                                       dyn_LOGFILEBASE, cli->pipe_name, op_num);
-                               prs_dump(dump_name, op_num, out_data);
+                               if (asprintf(&dump_name, "%s/reply_%s_%d",
+                                               get_dyn_LOGFILEBASE(), cli->pipe_name,
+                                               op_num) > 0) {
+                                       prs_dump(dump_name, op_num, out_data);
+                                       SAFE_FREE(dump_name);
+                               }
                        }
 
                        return ret;
@@ -1588,10 +1597,10 @@ NTSTATUS rpc_api_pipe_req(struct rpc_pipe_client *cli,
  Set the handle state.
 ****************************************************************************/
 
-static BOOL rpc_pipe_set_hnd_state(struct rpc_pipe_client *cli,
+static bool rpc_pipe_set_hnd_state(struct rpc_pipe_client *cli,
                                   const char *pipe_name, uint16 device_state)
 {
-       BOOL state_set = False;
+       bool state_set = False;
        char param[2];
        uint16 setup[2]; /* only need 2 uint16 setup parameters */
        char *rparam = NULL;
@@ -1634,58 +1643,14 @@ static BOOL rpc_pipe_set_hnd_state(struct rpc_pipe_client *cli,
  Check the rpc bind acknowledge response.
 ****************************************************************************/
 
-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)
+static bool check_bind_response(RPC_HDR_BA *hdr_ba, const RPC_IFACE *transfer)
 {
        if ( hdr_ba->addr.len == 0) {
                DEBUG(4,("Ignoring length check -- ASU bug (server didn't fill in the pipe name correctly)"));
        }
 
-# if 0 /* JERRY -- apparently ASU forgets to fill in the server pipe name sometimes */
-       if ( !strequal(hdr_ba->addr.str, pipe_names[pipe_idx].client_pipe) &&
-            !strequal(hdr_ba->addr.str, pipe_names[pipe_idx].server_pipe) )
-       {
-               DEBUG(4,("bind_rpc_pipe: pipe_name %s != expected pipe %s.  oh well!\n",
-                        pipe_names[i].server_pipe ,hdr_ba->addr.str));
-               return False;
-       }
-       
-       DEBUG(5,("bind_rpc_pipe: server pipe_name found: %s\n", pipe_names[i].server_pipe ));
-
-       if (pipe_names[pipe_idx].server_pipe == NULL) {
-               DEBUG(2,("bind_rpc_pipe: pipe name %s unsupported\n", hdr_ba->addr.str));
-               return False;
-       }
-#endif         /* JERRY */
-
        /* check the transfer syntax */
-       if ((hdr_ba->transfer.version != transfer->version) ||
+       if ((hdr_ba->transfer.if_version != transfer->if_version) ||
             (memcmp(&hdr_ba->transfer.uuid, &transfer->uuid, sizeof(transfer->uuid)) !=0)) {
                DEBUG(2,("bind_rpc_pipe: transfer syntax differs\n"));
                return False;
@@ -1773,8 +1738,8 @@ static NTSTATUS rpc_finish_auth3_bind(struct rpc_pipe_client *cli,
                                enum pipe_auth_type auth_type,
                                enum pipe_auth_level auth_level)
 {
-       DATA_BLOB server_response = data_blob(NULL,0);
-       DATA_BLOB client_reply = data_blob(NULL,0);
+       DATA_BLOB server_response = data_blob_null;
+       DATA_BLOB client_reply = data_blob_null;
        RPC_HDR_AUTH hdr_auth;
        NTSTATUS nt_status;
        prs_struct rpc_out;
@@ -1804,10 +1769,11 @@ static NTSTATUS rpc_finish_auth3_bind(struct rpc_pipe_client *cli,
        
        if (!NT_STATUS_IS_OK(nt_status)) {
                DEBUG(0,("rpc_finish_auth3_bind: NTLMSSP update using server blob failed.\n"));
+               data_blob_free(&server_response);
                return nt_status;
        }
 
-       prs_init(&rpc_out, 0, prs_get_mem_context(rbuf), MARSHALL);
+       prs_init_empty(&rpc_out, prs_get_mem_context(rbuf), MARSHALL);
 
        nt_status = create_rpc_bind_auth3(cli, rpc_call_id,
                                auth_type, auth_level,
@@ -1834,7 +1800,7 @@ static NTSTATUS rpc_finish_auth3_bind(struct rpc_pipe_client *cli,
 
        DEBUG(5,("rpc_send_auth_auth3: Remote machine %s pipe %s "
                "fnum 0x%x sent auth3 response ok.\n",
-               cli->cli->desthost,
+               cli->desthost,
                cli->pipe_name,
                (unsigned int)cli->fnum));
 
@@ -1850,8 +1816,8 @@ static NTSTATUS rpc_finish_auth3_bind(struct rpc_pipe_client *cli,
  ********************************************************************/
 
 static NTSTATUS create_rpc_alter_context(uint32 rpc_call_id,
-                                       RPC_IFACE *abstract,
-                                       RPC_IFACE *transfer,
+                                       const RPC_IFACE *abstract,
+                                       const RPC_IFACE *transfer,
                                        enum pipe_auth_level auth_level,
                                        const DATA_BLOB *pauth_blob, /* spnego auth blob already created. */
                                        prs_struct *rpc_out)
@@ -1861,7 +1827,8 @@ static NTSTATUS create_rpc_alter_context(uint32 rpc_call_id,
        NTSTATUS ret = NT_STATUS_OK;
 
        ZERO_STRUCT(hdr_auth);
-       prs_init(&auth_info, RPC_HDR_AUTH_LEN, prs_get_mem_context(rpc_out), MARSHALL);
+       if (!prs_init(&auth_info, RPC_HDR_AUTH_LEN, prs_get_mem_context(rpc_out), MARSHALL))
+               return NT_STATUS_NO_MEMORY;
 
        /* We may change the pad length before marshalling. */
        init_rpc_hdr_auth(&hdr_auth, RPC_SPNEGO_AUTH_TYPE, (int)auth_level, 0, 1);
@@ -1893,15 +1860,15 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind(struct rpc_pipe_client *cli,
                                 RPC_HDR *phdr,
                                 prs_struct *rbuf,
                                 uint32 rpc_call_id,
-                               RPC_IFACE *abstract,
-                               RPC_IFACE *transfer,
+                               const RPC_IFACE *abstract,
+                               const RPC_IFACE *transfer,
                                 enum pipe_auth_type auth_type,
                                 enum pipe_auth_level auth_level)
 {
-       DATA_BLOB server_spnego_response = data_blob(NULL,0);
-       DATA_BLOB server_ntlm_response = data_blob(NULL,0);
-       DATA_BLOB client_reply = data_blob(NULL,0);
-       DATA_BLOB tmp_blob = data_blob(NULL, 0);
+       DATA_BLOB server_spnego_response = data_blob_null;
+       DATA_BLOB server_ntlm_response = data_blob_null;
+       DATA_BLOB client_reply = data_blob_null;
+       DATA_BLOB tmp_blob = data_blob_null;
        RPC_HDR_AUTH hdr_auth;
        NTSTATUS nt_status;
        prs_struct rpc_out;
@@ -1951,10 +1918,10 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind(struct rpc_pipe_client *cli,
        tmp_blob = spnego_gen_auth(client_reply);
        data_blob_free(&client_reply);
        client_reply = tmp_blob;
-       tmp_blob = data_blob(NULL,0); /* Ensure it's safe to free this just in case. */
+       tmp_blob = data_blob_null; /* Ensure it's safe to free this just in case. */
 
        /* Now prepare the alter context pdu. */
-       prs_init(&rpc_out, 0, prs_get_mem_context(rbuf), MARSHALL);
+       prs_init_empty(&rpc_out, prs_get_mem_context(rbuf), MARSHALL);
 
        nt_status = create_rpc_alter_context(rpc_call_id,
                                                abstract,
@@ -1972,7 +1939,7 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind(struct rpc_pipe_client *cli,
 
        /* Initialize the returning data struct. */
        prs_mem_free(rbuf);
-       prs_init(rbuf, 0, cli->cli->mem_ctx, UNMARSHALL);
+       prs_init_empty(rbuf, talloc_tos(), UNMARSHALL);
 
        nt_status = rpc_api_pipe(cli, &rpc_out, rbuf, RPC_ALTCONTRESP);
        if (!NT_STATUS_IS_OK(nt_status)) {
@@ -2000,7 +1967,7 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind(struct rpc_pipe_client *cli,
        prs_copy_data_out((char *)server_spnego_response.data, rbuf, phdr->auth_len);
 
        /* Check we got a valid auth response. */
-       if (!spnego_parse_auth_response(server_spnego_response, NT_STATUS_OK, &tmp_blob)) {
+       if (!spnego_parse_auth_response(server_spnego_response, NT_STATUS_OK, OID_NTLMSSP, &tmp_blob)) {
                data_blob_free(&server_spnego_response);
                data_blob_free(&tmp_blob);
                return NT_STATUS_INVALID_PARAMETER;
@@ -2011,7 +1978,7 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind(struct rpc_pipe_client *cli,
 
        DEBUG(5,("rpc_finish_spnego_ntlmssp_bind: alter context request to "
                "remote machine %s pipe %s fnum 0x%x.\n",
-               cli->cli->desthost,
+               cli->desthost,
                cli->pipe_name,
                (unsigned int)cli->fnum));
 
@@ -2028,8 +1995,6 @@ static NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
 {
        RPC_HDR hdr;
        RPC_HDR_BA hdr_ba;
-       RPC_IFACE abstract;
-       RPC_IFACE transfer;
        prs_struct rpc_out;
        prs_struct rbuf;
        uint32 rpc_call_id;
@@ -2041,17 +2006,14 @@ static NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
                (unsigned int)auth_type,
                (unsigned int)auth_level ));
 
-       if (!valid_pipe_name(cli->pipe_idx, &abstract, &transfer)) {
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
-       prs_init(&rpc_out, 0, cli->cli->mem_ctx, MARSHALL);
+       prs_init_empty(&rpc_out, talloc_tos(), MARSHALL);
 
        rpc_call_id = get_rpc_call_id();
 
        /* Marshall the outgoing data. */
        status = create_rpc_bind_req(cli, &rpc_out, rpc_call_id,
-                               &abstract, &transfer,
+                               cli->abstract_syntax,
+                               cli->transfer_syntax,
                                auth_type,
                                auth_level);
 
@@ -2061,7 +2023,7 @@ static NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
        }
 
        /* Initialize the incoming data struct. */
-       prs_init(&rbuf, 0, cli->cli->mem_ctx, UNMARSHALL);
+       prs_init_empty(&rbuf, talloc_tos(), UNMARSHALL);
 
        /* send data on \PIPE\.  receive a response */
        status = rpc_api_pipe(cli, &rpc_out, &rbuf, RPC_BINDACK);
@@ -2074,7 +2036,7 @@ static NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
 
        DEBUG(3,("rpc_pipe_bind: Remote machine %s pipe %s "
                "fnum 0x%x bind request returned ok.\n",
-               cli->cli->desthost,
+               cli->desthost,
                cli->pipe_name,
                (unsigned int)cli->fnum));
 
@@ -2091,7 +2053,7 @@ static NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
                return NT_STATUS_BUFFER_TOO_SMALL;
        }
 
-       if(!check_bind_response(&hdr_ba, cli->pipe_idx, &transfer)) {
+       if(!check_bind_response(&hdr_ba, cli->transfer_syntax)) {
                DEBUG(2,("rpc_pipe_bind: check_bind_response failed.\n"));
                prs_mem_free(&rbuf);
                return NT_STATUS_BUFFER_TOO_SMALL;
@@ -2121,7 +2083,8 @@ static NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
                case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP:
                        /* Need to send alter context request and reply. */
                        status = rpc_finish_spnego_ntlmssp_bind(cli, &hdr, &rbuf, rpc_call_id,
-                                               &abstract, &transfer,
+                                               cli->abstract_syntax,
+                                               cli->transfer_syntax,
                                                auth_type, auth_level);
                        if (!NT_STATUS_IS_OK(status)) {
                                prs_mem_free(&rbuf);
@@ -2139,6 +2102,24 @@ static NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
                        return NT_STATUS_INVALID_INFO_CLASS;
        }
 
+       /* For NTLMSSP ensure the server gave us the auth_level we wanted. */
+       if (auth_type == PIPE_AUTH_TYPE_NTLMSSP || auth_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) {
+               if (auth_level == PIPE_AUTH_LEVEL_INTEGRITY) {
+                       if (!(cli->auth.a_u.ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN)) {
+                               DEBUG(0,("cli_finish_bind_auth: requested NTLMSSSP signing and server refused.\n"));
+                               prs_mem_free(&rbuf);
+                               return NT_STATUS_INVALID_PARAMETER;
+                       }
+               }
+               if (auth_level == PIPE_AUTH_LEVEL_INTEGRITY) {
+                       if (!(cli->auth.a_u.ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL)) {
+                               DEBUG(0,("cli_finish_bind_auth: requested NTLMSSSP sealing and server refused.\n"));
+                               prs_mem_free(&rbuf);
+                               return NT_STATUS_INVALID_PARAMETER;
+                       }
+               }
+       }
+
        /* Pipe is bound - set up auth_type and auth_level data. */
 
        cli->auth.auth_type = auth_type;
@@ -2148,63 +2129,126 @@ static NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
        return NT_STATUS_OK;
 }
 
+unsigned int rpccli_set_timeout(struct rpc_pipe_client *cli,
+                               unsigned int timeout)
+{
+       return cli_set_timeout(cli->cli, timeout);
+}
+
+bool rpccli_is_pipe_idx(struct rpc_pipe_client *cli, int pipe_idx)
+{
+       return (cli->abstract_syntax == pipe_names[pipe_idx].abstr_syntax);
+}
+
+static int rpc_pipe_destructor(struct rpc_pipe_client *p)
+{
+       bool ret;
+
+       ret = cli_close(p->cli, p->fnum);
+       if (!ret) {
+               DEBUG(1, ("rpc_pipe_destructor: cli_close failed on pipe %s, "
+                         "fnum 0x%x to machine %s.  Error was %s\n",
+                         p->pipe_name, (int) p->fnum,
+                         p->desthost, cli_errstr(p->cli)));
+       }
+
+       if (p->auth.cli_auth_data_free_func) {
+               (*p->auth.cli_auth_data_free_func)(&p->auth);
+       }
+
+       DEBUG(10, ("rpc_pipe_destructor: closed pipe %s to machine %s\n",
+                  p->pipe_name, p->desthost ));
+
+       DLIST_REMOVE(p->cli->pipe_list, p);
+
+       return ret ? -1 : 0;
+}
+
 /****************************************************************************
  Open a named pipe over SMB to a remote server.
+ *
+ * CAVEAT CALLER OF THIS FUNCTION:
+ *    The returned rpc_pipe_client saves a copy of the cli_state cli pointer,
+ *    so be sure that this function is called AFTER any structure (vs pointer)
+ *    assignment of the cli.  In particular, libsmbclient does structure
+ *    assignments of cli, which invalidates the data in the returned
+ *    rpc_pipe_client if this function is called before the structure assignment
+ *    of cli.
+ * 
  ****************************************************************************/
 
 static struct rpc_pipe_client *cli_rpc_pipe_open(struct cli_state *cli, int pipe_idx, NTSTATUS *perr)
 {
-       TALLOC_CTX *mem_ctx;
        struct rpc_pipe_client *result;
        int fnum;
 
        *perr = NT_STATUS_NO_MEMORY;
 
-       /* The pipe name index must fall within our array */
-       SMB_ASSERT((pipe_idx >= 0) && (pipe_idx < PI_MAX_PIPES));
+       /* sanity check to protect against crashes */
 
-       mem_ctx = talloc_init("struct rpc_pipe_client");
-       if (mem_ctx == NULL) {
+       if ( !cli ) {
+               *perr = NT_STATUS_INVALID_HANDLE;
                return NULL;
        }
 
-       result = TALLOC_ZERO_P(mem_ctx, struct rpc_pipe_client);
+       /* The pipe name index must fall within our array */
+       SMB_ASSERT((pipe_idx >= 0) && (pipe_idx < PI_MAX_PIPES));
+
+       result = TALLOC_ZERO_P(NULL, struct rpc_pipe_client);
        if (result == NULL) {
+               *perr = NT_STATUS_NO_MEMORY;
                return NULL;
        }
 
-       result->mem_ctx = mem_ctx;
-
        result->pipe_name = cli_get_pipe_name(pipe_idx);
 
-       fnum = cli_nt_create(cli, result->pipe_name, DESIRED_ACCESS_PIPE);
-
-       if (fnum == -1) {
-               DEBUG(0,("cli_rpc_pipe_open: cli_nt_create failed on pipe %s "
-                        "to machine %s.  Error was %s\n",
-                        result->pipe_name, cli->desthost,
-                        cli_errstr(cli)));
-               *perr = cli_get_nt_error(cli);
-               talloc_destroy(result->mem_ctx);
-               return NULL;
-       }
-
-       result->fnum = fnum;
        result->cli = cli;
-       result->pipe_idx = pipe_idx;
+       result->abstract_syntax = pipe_names[pipe_idx].abstr_syntax;
+       result->transfer_syntax = pipe_names[pipe_idx].trans_syntax;
        result->auth.auth_type = PIPE_AUTH_TYPE_NONE;
        result->auth.auth_level = PIPE_AUTH_LEVEL_NONE;
 
+       result->domain = talloc_strdup(result, cli->domain);
+       result->user_name = talloc_strdup(result, cli->user_name);
+       result->desthost = talloc_strdup(result, cli->desthost);
+       result->srv_name_slash = talloc_asprintf_strupper_m(
+               result, "\\\\%s", result->desthost);
+
+       if ((result->domain == NULL)
+           || (result->user_name == NULL)
+           || (result->desthost == NULL)
+           || (result->srv_name_slash == NULL)) {
+               *perr = NT_STATUS_NO_MEMORY;
+               TALLOC_FREE(result);
+               return NULL;
+       }
+
        if (pipe_idx == PI_NETLOGON) {
                /* Set up a netlogon credential chain for a netlogon pipe. */
-               result->dc = TALLOC_ZERO_P(mem_ctx, struct dcinfo);
+               result->dc = TALLOC_ZERO_P(result, struct dcinfo);
                if (result->dc == NULL) {
-                       talloc_destroy(result->mem_ctx);
+                       *perr = NT_STATUS_NO_MEMORY;
+                       TALLOC_FREE(result);
                        return NULL;
                }
        }
 
+       fnum = cli_nt_create(cli, result->pipe_name, DESIRED_ACCESS_PIPE);
+       if (fnum == -1) {
+               DEBUG(1,("cli_rpc_pipe_open: cli_nt_create failed on pipe %s "
+                        "to machine %s.  Error was %s\n",
+                        result->pipe_name, cli->desthost,
+                        cli_errstr(cli)));
+               *perr = cli_get_nt_error(cli);
+               talloc_destroy(result);
+               return NULL;
+       }
+
+       result->fnum = fnum;
+
        DLIST_ADD(cli->pipe_list, result);
+       talloc_set_destructor(result, rpc_pipe_destructor);
+
        *perr = NT_STATUS_OK;
 
        return result;
@@ -2225,9 +2269,15 @@ struct rpc_pipe_client *cli_rpc_pipe_open_noauth(struct cli_state *cli, int pipe
 
        *perr = rpc_pipe_bind(result, PIPE_AUTH_TYPE_NONE, PIPE_AUTH_LEVEL_NONE);
        if (!NT_STATUS_IS_OK(*perr)) {
-               DEBUG(0, ("cli_rpc_pipe_open_noauth: rpc_pipe_bind for pipe %s failed with error %s\n",
+               int lvl = 0;
+               if (rpccli_is_pipe_idx(result, PI_DSSETUP)) {
+                       /* non AD domains just don't have this pipe, avoid
+                        * level 0 statement in that case - gd */
+                       lvl = 3;
+               }
+               DEBUG(lvl, ("cli_rpc_pipe_open_noauth: rpc_pipe_bind for pipe %s failed with error %s\n",
                        cli_get_pipe_name(pipe_idx), nt_errstr(*perr) ));
-               cli_rpc_pipe_close(result);
+               TALLOC_FREE(result);
                return NULL;
        }
 
@@ -2272,8 +2322,17 @@ static struct rpc_pipe_client *cli_rpc_pipe_open_ntlmssp_internal(struct cli_sta
        
        result->auth.cli_auth_data_free_func = cli_ntlmssp_auth_free;
 
-       result->domain = domain;
-       result->user_name = username;
+       TALLOC_FREE(result->domain);
+       TALLOC_FREE(result->user_name);
+
+       result->domain = talloc_strdup(result, domain);
+       result->user_name = talloc_strdup(result, username);
+
+       if ((result->domain == NULL) || (result->user_name == NULL)) {
+               *perr = NT_STATUS_NO_MEMORY;
+               goto err;
+       }
+
        pwd_set_cleartext(&result->pwd, password);
 
        *perr = ntlmssp_client_start(&ntlmssp_state);
@@ -2283,12 +2342,12 @@ static struct rpc_pipe_client *cli_rpc_pipe_open_ntlmssp_internal(struct cli_sta
 
        result->auth.a_u.ntlmssp_state = ntlmssp_state;
 
-       *perr = ntlmssp_set_username(ntlmssp_state, cli->user_name);
+       *perr = ntlmssp_set_username(ntlmssp_state, username);
        if (!NT_STATUS_IS_OK(*perr)) {
                goto err;
        }
 
-       *perr = ntlmssp_set_domain(ntlmssp_state, cli->domain); 
+       *perr = ntlmssp_set_domain(ntlmssp_state, domain);
        if (!NT_STATUS_IS_OK(*perr)) {
                goto err;
        }
@@ -2321,8 +2380,8 @@ static struct rpc_pipe_client *cli_rpc_pipe_open_ntlmssp_internal(struct cli_sta
                goto err;
        }
 
-       DEBUG(10,("cli_rpc_pipe_open_ntlmssp_internal: opened pipe %s to machine %s and"
-               "bound NTLMSSP as user %s\\%s.\n",
+       DEBUG(10,("cli_rpc_pipe_open_ntlmssp_internal: opened pipe %s to "
+               "machine %s and bound NTLMSSP as user %s\\%s.\n",
                result->pipe_name, cli->desthost,
                domain, username ));
 
@@ -2330,7 +2389,7 @@ static struct rpc_pipe_client *cli_rpc_pipe_open_ntlmssp_internal(struct cli_sta
 
   err:
 
-       cli_rpc_pipe_close(result);
+       TALLOC_FREE(result);
        return NULL;
 }
 
@@ -2381,66 +2440,77 @@ struct rpc_pipe_client *cli_rpc_pipe_open_spnego_ntlmssp(struct cli_state *cli,
 }
 
 /****************************************************************************
Open a netlogon pipe and get the schannel session key.
 Get a the schannel session key out of an already opened netlogon pipe.
  ****************************************************************************/
-
-static struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli,
-                                                       const char *domain,
-                                                       NTSTATUS *perr)
+static bool get_schannel_session_key_common(struct rpc_pipe_client *netlogon_pipe,
+                                           struct cli_state *cli,
+                                           const char *domain,
+                                           uint32 *pneg_flags,
+                                           NTSTATUS *perr)
 {
-       uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS|NETLOGON_NEG_SCHANNEL;
-       struct rpc_pipe_client *netlogon_pipe = NULL;
        uint32 sec_chan_type = 0;
-       char machine_pwd[16];
-       fstring machine_account;
-
-       netlogon_pipe = cli_rpc_pipe_open_noauth(cli, PI_NETLOGON, perr);
-       if (!netlogon_pipe) {
-               return NULL;
-       }
+       unsigned char machine_pwd[16];
+       const char *machine_account;
 
        /* Get the machine account credentials from secrets.tdb. */
-       if (!get_trust_pw(domain, machine_pwd, &sec_chan_type)) {
+       if (!get_trust_pw_hash(domain, machine_pwd, &machine_account,
+                              &sec_chan_type))
+       {
                DEBUG(0, ("get_schannel_session_key: could not fetch "
                        "trust account password for domain '%s'\n",
                        domain));
-               cli_rpc_pipe_close(netlogon_pipe);
                *perr = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
-               return NULL;
+               return false;
        }
 
-       if ( IS_DC ) {
-               fstrcpy( machine_account, lp_workgroup() );
-        } else {
-                /* Hmmm. Is this correct for trusted domains when we're a member server ? JRA. */
-                if (strequal(domain, lp_workgroup())) {
-                        fstrcpy(machine_account, global_myname());
-                } else {
-                        fstrcpy(machine_account, domain);
-                }
-        }
-
        *perr = rpccli_netlogon_setup_creds(netlogon_pipe,
-                                       cli->desthost,
-                                       domain,
-                                       machine_account,
+                                       cli->desthost, /* server name */
+                                       domain,        /* domain */
+                                       global_myname(), /* client name */
+                                       machine_account, /* machine account name */
                                        machine_pwd,
                                        sec_chan_type,
-                                       &neg_flags);
+                                       pneg_flags);
 
        if (!NT_STATUS_IS_OK(*perr)) {
-               DEBUG(3,("get_schannel_session_key: rpccli_netlogon_setup_creds "
-                       "failed with result %s\n",
-                       nt_errstr(*perr) ));
-               cli_rpc_pipe_close(netlogon_pipe);
-               return NULL;
+               DEBUG(3,("get_schannel_session_key_common: rpccli_netlogon_setup_creds "
+                       "failed with result %s to server %s, domain %s, machine account %s.\n",
+                       nt_errstr(*perr), cli->desthost, domain, machine_account ));
+               return false;
        }
 
-       if ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0) {
+       if (((*pneg_flags) & NETLOGON_NEG_SCHANNEL) == 0) {
                DEBUG(3, ("get_schannel_session_key: Server %s did not offer schannel\n",
                        cli->desthost));
-               cli_rpc_pipe_close(netlogon_pipe);
                *perr = NT_STATUS_INVALID_NETWORK_RESPONSE;
+               return false;
+       }
+
+       return true;
+}
+
+/****************************************************************************
+ Open a netlogon pipe and get the schannel session key.
+ Now exposed to external callers.
+ ****************************************************************************/
+
+
+struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli,
+                                                       const char *domain,
+                                                       uint32 *pneg_flags,
+                                                       NTSTATUS *perr)
+{
+       struct rpc_pipe_client *netlogon_pipe = NULL;
+
+       netlogon_pipe = cli_rpc_pipe_open_noauth(cli, PI_NETLOGON, perr);
+       if (!netlogon_pipe) {
+               return NULL;
+       }
+
+       if (!get_schannel_session_key_common(netlogon_pipe, cli, domain,
+                                            pneg_flags, perr))
+       {
+               TALLOC_FREE(netlogon_pipe);
                return NULL;
        }
 
@@ -2467,21 +2537,29 @@ struct rpc_pipe_client *cli_rpc_pipe_open_schannel_with_key(struct cli_state *cl
                return NULL;
        }
 
-       result->auth.a_u.schannel_auth = TALLOC_ZERO_P(result->mem_ctx, struct schannel_auth_struct);
+       result->auth.a_u.schannel_auth = TALLOC_ZERO_P(
+               result, struct schannel_auth_struct);
        if (!result->auth.a_u.schannel_auth) {
-               cli_rpc_pipe_close(result);
+               TALLOC_FREE(result);
+               *perr = NT_STATUS_NO_MEMORY;
+               return NULL;
+       }
+
+       TALLOC_FREE(result->domain);
+       result->domain = talloc_strdup(result, domain);
+       if (result->domain == NULL) {
+               TALLOC_FREE(result);
                *perr = NT_STATUS_NO_MEMORY;
                return NULL;
        }
 
-       result->domain = domain;
        memcpy(result->auth.a_u.schannel_auth->sess_key, pdc->sess_key, 16);
 
        *perr = rpc_pipe_bind(result, PIPE_AUTH_TYPE_SCHANNEL, auth_level);
        if (!NT_STATUS_IS_OK(*perr)) {
                DEBUG(0, ("cli_rpc_pipe_open_schannel_with_key: cli_rpc_pipe_bind failed with error %s\n",
                        nt_errstr(*perr) ));
-               cli_rpc_pipe_close(result);
+               TALLOC_FREE(result);
                return NULL;
        }
 
@@ -2508,61 +2586,20 @@ static struct rpc_pipe_client *get_schannel_session_key_auth_ntlmssp(struct cli_
                                                        const char *domain,
                                                        const char *username,
                                                        const char *password,
+                                                       uint32 *pneg_flags,
                                                        NTSTATUS *perr)
 {
-       uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS|NETLOGON_NEG_SCHANNEL;
        struct rpc_pipe_client *netlogon_pipe = NULL;
-       uint32 sec_chan_type = 0;
-       char machine_pwd[16];
-       fstring machine_account;
 
        netlogon_pipe = cli_rpc_pipe_open_spnego_ntlmssp(cli, PI_NETLOGON, PIPE_AUTH_LEVEL_PRIVACY, domain, username, password, perr);
        if (!netlogon_pipe) {
                return NULL;
        }
 
-       /* Get the machine account credentials from secrets.tdb. */
-       if (!get_trust_pw(domain, machine_pwd, &sec_chan_type)) {
-               DEBUG(0, ("get_schannel_session_key_auth_ntlmssp: could not fetch "
-                       "trust account password for domain '%s'\n",
-                       domain));
-               cli_rpc_pipe_close(netlogon_pipe);
-               *perr = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
-               return NULL;
-       }
-
-       if ( IS_DC ) {
-               fstrcpy( machine_account, lp_workgroup() );
-        } else {
-                /* Hmmm. Is this correct for trusted domains when we're a member server ? JRA. */
-                if (strequal(domain, lp_workgroup())) {
-                        fstrcpy(machine_account, global_myname());
-                } else {
-                        fstrcpy(machine_account, domain);
-                }
-        }
-
-       *perr = rpccli_netlogon_setup_creds(netlogon_pipe,
-                                       cli->desthost,
-                                       domain,
-                                       machine_account,
-                                       machine_pwd,
-                                       sec_chan_type,
-                                       &neg_flags);
-
-       if (!NT_STATUS_IS_OK(*perr)) {
-               DEBUG(3,("get_schannel_session_key_auth_ntlmssp: rpccli_netlogon_setup_creds "
-                       "failed with result %s\n",
-                       nt_errstr(*perr) ));
-               cli_rpc_pipe_close(netlogon_pipe);
-               return NULL;
-       }
-
-       if ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0) {
-               DEBUG(3, ("get_schannel_session_key_auth_ntlmssp: Server %s did not offer schannel\n",
-                       cli->desthost));
-               cli_rpc_pipe_close(netlogon_pipe);
-               *perr = NT_STATUS_INVALID_NETWORK_RESPONSE;
+       if (!get_schannel_session_key_common(netlogon_pipe, cli, domain,
+                                            pneg_flags, perr))
+       {
+               TALLOC_FREE(netlogon_pipe);
                return NULL;
        }
 
@@ -2575,7 +2612,7 @@ static struct rpc_pipe_client *get_schannel_session_key_auth_ntlmssp(struct cli_
  uses an ntlmssp bind to get the session key.
  ****************************************************************************/
 
-struct rpc_pipe_client *cli_rpc_pipe_open_ntlmttp_auth_schannel(struct cli_state *cli,
+struct rpc_pipe_client *cli_rpc_pipe_open_ntlmssp_auth_schannel(struct cli_state *cli,
                                                 int pipe_idx,
                                                enum pipe_auth_level auth_level,
                                                 const char *domain,
@@ -2583,10 +2620,12 @@ struct rpc_pipe_client *cli_rpc_pipe_open_ntlmttp_auth_schannel(struct cli_state
                                                const char *password,
                                                NTSTATUS *perr)
 {
+       uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
        struct rpc_pipe_client *netlogon_pipe = NULL;
        struct rpc_pipe_client *result = NULL;
 
-       netlogon_pipe = get_schannel_session_key_auth_ntlmssp(cli, domain, username, password, perr);
+       netlogon_pipe = get_schannel_session_key_auth_ntlmssp(cli, domain, username,
+                                                       password, &neg_flags, perr);
        if (!netlogon_pipe) {
                DEBUG(0,("cli_rpc_pipe_open_ntlmssp_auth_schannel: failed to get schannel session "
                        "key from server %s for domain %s.\n",
@@ -2599,7 +2638,7 @@ struct rpc_pipe_client *cli_rpc_pipe_open_ntlmttp_auth_schannel(struct cli_state
                                domain, netlogon_pipe->dc, perr);
 
        /* Now we've bound using the session key we can close the netlog pipe. */
-       cli_rpc_pipe_close(netlogon_pipe);
+       TALLOC_FREE(netlogon_pipe);
 
        return result;
 }
@@ -2615,10 +2654,11 @@ struct rpc_pipe_client *cli_rpc_pipe_open_schannel(struct cli_state *cli,
                                                 const char *domain,
                                                NTSTATUS *perr)
 {
+       uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
        struct rpc_pipe_client *netlogon_pipe = NULL;
        struct rpc_pipe_client *result = NULL;
 
-       netlogon_pipe = get_schannel_session_key(cli, domain, perr);
+       netlogon_pipe = get_schannel_session_key(cli, domain, &neg_flags, perr);
        if (!netlogon_pipe) {
                DEBUG(0,("cli_rpc_pipe_open_schannel: failed to get schannel session "
                        "key from server %s for domain %s.\n",
@@ -2631,11 +2671,13 @@ struct rpc_pipe_client *cli_rpc_pipe_open_schannel(struct cli_state *cli,
                                domain, netlogon_pipe->dc, perr);
 
        /* Now we've bound using the session key we can close the netlog pipe. */
-       cli_rpc_pipe_close(netlogon_pipe);
+       TALLOC_FREE(netlogon_pipe);
 
        return result;
 }
 
+#ifdef HAVE_KRB5
+
 /****************************************************************************
  Free function for the kerberos spcific data.
  ****************************************************************************/
@@ -2645,6 +2687,8 @@ static void kerberos_auth_struct_free(struct cli_pipe_auth_data *a)
        data_blob_free(&a->a_u.kerberos_auth->session_key);
 }
 
+#endif
+
 /****************************************************************************
  Open a named pipe to an SMB server and bind using krb5 (bind type 16).
  The idea is this can be called with service_princ, username and password all
@@ -2667,28 +2711,29 @@ struct rpc_pipe_client *cli_rpc_pipe_open_krb5(struct cli_state *cli,
                return NULL;
        }
 
-       /* Default service principal is "host/server@realm" */
+       /* Default service principal is "desthost$@realm" */
        if (!service_princ) {
-               service_princ = talloc_asprintf(result->mem_ctx, "host/%s@%s",
-                       cli->desthost, lp_realm() );
+               service_princ = talloc_asprintf(result, "%s$@%s",
+                                               cli->desthost, lp_realm() );
                if (!service_princ) {
-                       cli_rpc_pipe_close(result);
+                       TALLOC_FREE(result);
                        return NULL;
                }
        }
 
        /* Only get a new TGT if username/password are given. */
        if (username && password) {
-               int ret = kerberos_kinit_password(username, password, 0, NULL, NULL);
+               int ret = kerberos_kinit_password(username, password, 0, NULL);
                if (ret) {
-                       cli_rpc_pipe_close(result);
+                       TALLOC_FREE(result);
                        return NULL;
                }
        }
 
-       result->auth.a_u.kerberos_auth = TALLOC_ZERO_P(cli->mem_ctx, struct kerberos_auth_struct);
+       result->auth.a_u.kerberos_auth = TALLOC_ZERO_P(
+               result, struct kerberos_auth_struct);
        if (!result->auth.a_u.kerberos_auth) {
-               cli_rpc_pipe_close(result);
+               TALLOC_FREE(result);
                *perr = NT_STATUS_NO_MEMORY;
                return NULL;
        }
@@ -2700,7 +2745,7 @@ struct rpc_pipe_client *cli_rpc_pipe_open_krb5(struct cli_state *cli,
        if (!NT_STATUS_IS_OK(*perr)) {
                DEBUG(0, ("cli_rpc_pipe_open_krb5: cli_rpc_pipe_bind failed with error %s\n",
                        nt_errstr(*perr) ));
-               cli_rpc_pipe_close(result);
+               TALLOC_FREE(result);
                return NULL;
        }
 
@@ -2710,30 +2755,3 @@ struct rpc_pipe_client *cli_rpc_pipe_open_krb5(struct cli_state *cli,
        return NULL;
 #endif
 }
-
-#if 0 /* Moved to libsmb/clientgen.c */
-/****************************************************************************
- External interface.
- Close an open named pipe over SMB. Free any authentication data.
- ****************************************************************************/
-
-void cli_rpc_pipe_close(struct rpc_pipe_client *cli)
-{
-       if (!cli_close(cli->cli, cli->fnum)) {
-               DEBUG(0,("cli_rpc_pipe_close: cli_close failed on pipe %s "
-                        "to machine %s.  Error was %s\n",
-                        cli->pipe_name),
-                        cli->cli->desthost,
-                        cli_errstr(cli->cli)));
-       }
-
-       if (cli->auth.cli_auth_data_free_func) {
-               (*cli->auth.cli_auth_data_free_func)(&cli->auth);
-       }
-       DEBUG(10,("cli_rpc_pipe_close: closed pipe %s to machine %s\n",
-               cli->pipe_name, cli->cli->desthost ));
-
-       DLIST_REMOVE(cli->cli->pipe_list, cli);
-       talloc_destroy(cli->mem_ctx);   
-}
-#endif