s3:libsmb: make cli_ulogoff_send/recv static
[mat/samba.git] / source3 / libsmb / cliconnect.c
index 315c2ac7420f2cc4dcda77ed4216bcf64699fe7d..b91c3ebe43683a293bb55df983d7d4843567caa0 100644 (file)
 
 #include "includes.h"
 #include "libsmb/libsmb.h"
-#include "popt_common.h"
+#include "auth_info.h"
 #include "../libcli/auth/libcli_auth.h"
 #include "../libcli/auth/spnego.h"
 #include "smb_krb5.h"
-#include "../libcli/auth/ntlmssp.h"
+#include "../auth/ntlmssp/ntlmssp.h"
 #include "libads/kerberos_proto.h"
 #include "krb5_env.h"
 #include "../lib/util/tevent_ntstatus.h"
 #include "async_smb.h"
 #include "libsmb/nmblib.h"
-#include "read_smb.h"
-
-static const struct {
-       int prot;
-       const char name[24];
-} prots[10] = {
-       {PROTOCOL_CORE,         "PC NETWORK PROGRAM 1.0"},
-       {PROTOCOL_COREPLUS,     "MICROSOFT NETWORKS 1.03"},
-       {PROTOCOL_LANMAN1,      "MICROSOFT NETWORKS 3.0"},
-       {PROTOCOL_LANMAN1,      "LANMAN1.0"},
-       {PROTOCOL_LANMAN2,      "LM1.2X002"},
-       {PROTOCOL_LANMAN2,      "DOS LANMAN2.1"},
-       {PROTOCOL_LANMAN2,      "LANMAN2.1"},
-       {PROTOCOL_LANMAN2,      "Samba"},
-       {PROTOCOL_NT1,          "NT LANMAN 1.0"},
-       {PROTOCOL_NT1,          "NT LM 0.12"},
-};
+#include "librpc/ndr/libndr.h"
+#include "../libcli/smb/smbXcli_base.h"
+#include "smb2cli.h"
 
 #define STAR_SMBSERVER "*SMBSERVER"
 
@@ -60,15 +46,15 @@ static const struct {
 *******************************************************/
 
 static NTSTATUS smb_bytes_talloc_string(TALLOC_CTX *mem_ctx,
-                                       char *inbuf,
+                                       const uint8_t *hdr,
                                        char **dest,
                                        uint8_t *src,
                                        size_t srclen,
                                        ssize_t *destlen)
 {
        *destlen = clistr_pull_talloc(mem_ctx,
-                               inbuf,
-                               SVAL(inbuf, smb_flg2),
+                               (const char *)hdr,
+                               SVAL(hdr, HDR_FLG2),
                                dest,
                                (char *)src,
                                srclen,
@@ -86,18 +72,6 @@ static NTSTATUS smb_bytes_talloc_string(TALLOC_CTX *mem_ctx,
        return NT_STATUS_OK;
 }
 
-/**
- * Set the user session key for a connection
- * @param cli The cli structure to add it too
- * @param session_key The session key used.  (A copy of this is taken for the cli struct)
- *
- */
-
-static void cli_set_session_key (struct cli_state *cli, const DATA_BLOB session_key) 
-{
-       cli->user_session_key = data_blob(session_key.data, session_key.length);
-}
-
 /****************************************************************************
  Do an old lanman2 style session setup.
 ****************************************************************************/
@@ -122,7 +96,7 @@ static struct tevent_req *cli_session_setup_lanman2_send(
        uint16_t *vwv;
        uint8_t *bytes;
        char *tmp;
-       uint16_t sec_mode = cli_state_security_mode(cli);
+       uint16_t sec_mode = smb1cli_conn_server_security_mode(cli->conn);
 
        req = tevent_req_create(mem_ctx, &state,
                                struct cli_session_setup_lanman2_state);
@@ -152,7 +126,7 @@ static struct tevent_req *cli_session_setup_lanman2_send(
                        return tevent_req_post(req, ev);
                }
 
-               if (!SMBencrypt(pass, cli->secblob.data,
+               if (!SMBencrypt(pass, smb1cli_conn_server_challenge(cli->conn),
                                (uint8_t *)lm_response.data)) {
                        DEBUG(1, ("Password is > 14 chars in length, and is "
                                  "therefore incompatible with Lanman "
@@ -177,7 +151,7 @@ static struct tevent_req *cli_session_setup_lanman2_send(
                 * Plaintext mode needed, assume plaintext supplied.
                 */
                buf = talloc_array(talloc_tos(), uint8_t, 0);
-               buf = smb_bytes_push_str(buf, cli_ucs2(cli), pass, passlen+1,
+               buf = smb_bytes_push_str(buf, smbXcli_conn_use_unicode(cli->conn), pass, passlen+1,
                                         &converted_size);
                if (tevent_req_nomem(buf, req)) {
                        return tevent_req_post(req, ev);
@@ -195,7 +169,7 @@ static struct tevent_req *cli_session_setup_lanman2_send(
        SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
        SSVAL(vwv+3, 0, 2);
        SSVAL(vwv+4, 0, 1);
-       SIVAL(vwv+5, 0, cli_state_server_session_key(cli));
+       SIVAL(vwv+5, 0, smb1cli_conn_server_session_key(cli->conn));
        SSVAL(vwv+7, 0, lm_response.length);
 
        bytes = talloc_array(state, uint8_t, lm_response.length);
@@ -211,7 +185,7 @@ static struct tevent_req *cli_session_setup_lanman2_send(
        if (tevent_req_nomem(tmp, req)) {
                return tevent_req_post(req, ev);
        }
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1,
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), tmp, strlen(tmp)+1,
                                   NULL);
        TALLOC_FREE(tmp);
 
@@ -219,10 +193,10 @@ static struct tevent_req *cli_session_setup_lanman2_send(
        if (tevent_req_nomem(tmp, req)) {
                return tevent_req_post(req, ev);
        }
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1,
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), tmp, strlen(tmp)+1,
                                   NULL);
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Unix", 5, NULL);
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Samba", 6, NULL);
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Unix", 5, NULL);
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Samba", 6, NULL);
 
        if (tevent_req_nomem(bytes, req)) {
                return tevent_req_post(req, ev);
@@ -246,7 +220,7 @@ static void cli_session_setup_lanman2_done(struct tevent_req *subreq)
        struct cli_state *cli = state->cli;
        uint32_t num_bytes;
        uint8_t *in;
-       char *inbuf;
+       uint8_t *inhdr;
        uint8_t *bytes;
        uint8_t *p;
        NTSTATUS status;
@@ -262,14 +236,13 @@ static void cli_session_setup_lanman2_done(struct tevent_req *subreq)
                return;
        }
 
-       inbuf = (char *)in;
+       inhdr = in + NBT_HDR_SIZE;
        p = bytes;
 
-       cli_state_set_uid(state->cli, SVAL(inbuf, smb_uid));
-       cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
+       cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
 
        status = smb_bytes_talloc_string(cli,
-                                       inbuf,
+                                       inhdr,
                                        &cli->server_os,
                                        p,
                                        bytes+num_bytes-p,
@@ -282,7 +255,7 @@ static void cli_session_setup_lanman2_done(struct tevent_req *subreq)
        p += ret;
 
        status = smb_bytes_talloc_string(cli,
-                                       inbuf,
+                                       inhdr,
                                        &cli->server_type,
                                        p,
                                        bytes+num_bytes-p,
@@ -295,7 +268,7 @@ static void cli_session_setup_lanman2_done(struct tevent_req *subreq)
        p += ret;
 
        status = smb_bytes_talloc_string(cli,
-                                       inbuf,
+                                       inhdr,
                                        &cli->server_domain,
                                        p,
                                        bytes+num_bytes-p,
@@ -319,40 +292,6 @@ static NTSTATUS cli_session_setup_lanman2_recv(struct tevent_req *req)
        return tevent_req_simple_recv_ntstatus(req);
 }
 
-static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli, const char *user,
-                                         const char *pass, size_t passlen,
-                                         const char *workgroup)
-{
-       TALLOC_CTX *frame = talloc_stackframe();
-       struct event_context *ev;
-       struct tevent_req *req;
-       NTSTATUS status = NT_STATUS_NO_MEMORY;
-
-       if (cli_has_async_calls(cli)) {
-               /*
-                * Can't use sync call while an async call is in flight
-                */
-               status = NT_STATUS_INVALID_PARAMETER;
-               goto fail;
-       }
-       ev = event_context_init(frame);
-       if (ev == NULL) {
-               goto fail;
-       }
-       req = cli_session_setup_lanman2_send(frame, ev, cli, user, pass, passlen,
-                                            workgroup);
-       if (req == NULL) {
-               goto fail;
-       }
-       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
-               goto fail;
-       }
-       status = cli_session_setup_lanman2_recv(req);
- fail:
-       TALLOC_FREE(frame);
-       return status;
-}
-
 /****************************************************************************
  Work out suitable capabilities to offer the server.
 ****************************************************************************/
@@ -360,16 +299,20 @@ static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli, const char *use
 static uint32_t cli_session_setup_capabilities(struct cli_state *cli,
                                               uint32_t sesssetup_capabilities)
 {
-       uint32_t client_capabilities = cli_state_capabilities(cli);
+       uint32_t client_capabilities = smb1cli_conn_capabilities(cli->conn);
 
        /*
         * We only send capabilities based on the mask for:
         * - client only flags
         * - flags used in both directions
         *
-        * We do not echo the server only flags.
+        * We do not echo the server only flags, except some legacy flags.
+        *
+        * SMB_CAP_LEGACY_CLIENT_MASK contains CAP_LARGE_READX and
+        * CAP_LARGE_WRITEX in order to allow us to do large reads
+        * against old Samba releases (<= 3.6.x).
         */
-       client_capabilities &= (SMB_CAP_BOTH_MASK | SMB_CAP_CLIENT_MASK);
+       client_capabilities &= (SMB_CAP_BOTH_MASK | SMB_CAP_LEGACY_CLIENT_MASK);
 
        /*
         * Session Setup specific flags CAP_DYNAMIC_REAUTH
@@ -397,7 +340,7 @@ struct cli_session_setup_guest_state {
 static void cli_session_setup_guest_done(struct tevent_req *subreq);
 
 struct tevent_req *cli_session_setup_guest_create(TALLOC_CTX *mem_ctx,
-                                                 struct event_context *ev,
+                                                 struct tevent_context *ev,
                                                  struct cli_state *cli,
                                                  struct tevent_req **psmbreq)
 {
@@ -420,7 +363,7 @@ struct tevent_req *cli_session_setup_guest_create(TALLOC_CTX *mem_ctx,
        SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
        SSVAL(vwv+3, 0, 2);
        SSVAL(vwv+4, 0, cli_state_get_vc_num(cli));
-       SIVAL(vwv+5, 0, cli_state_server_session_key(cli));
+       SIVAL(vwv+5, 0, smb1cli_conn_server_session_key(cli->conn));
        SSVAL(vwv+7, 0, 0);
        SSVAL(vwv+8, 0, 0);
        SSVAL(vwv+9, 0, 0);
@@ -429,12 +372,12 @@ struct tevent_req *cli_session_setup_guest_create(TALLOC_CTX *mem_ctx,
 
        bytes = talloc_array(state, uint8_t, 0);
 
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "",  1, /* username */
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "",  1, /* username */
                                   NULL);
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, /* workgroup */
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, /* workgroup */
                                   NULL);
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Unix", 5, NULL);
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Samba", 6, NULL);
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Unix", 5, NULL);
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Samba", 6, NULL);
 
        if (bytes == NULL) {
                TALLOC_FREE(req);
@@ -456,7 +399,7 @@ struct tevent_req *cli_session_setup_guest_create(TALLOC_CTX *mem_ctx,
 }
 
 struct tevent_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx,
-                                               struct event_context *ev,
+                                               struct tevent_context *ev,
                                                struct cli_state *cli)
 {
        struct tevent_req *req, *subreq;
@@ -467,8 +410,8 @@ struct tevent_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx,
                return NULL;
        }
 
-       status = cli_smb_req_send(subreq);
-       if (NT_STATUS_IS_OK(status)) {
+       status = smb1cli_req_chain_submit(&subreq, 1);
+       if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
                return tevent_req_post(req, ev);
        }
@@ -484,7 +427,7 @@ static void cli_session_setup_guest_done(struct tevent_req *subreq)
        struct cli_state *cli = state->cli;
        uint32_t num_bytes;
        uint8_t *in;
-       char *inbuf;
+       uint8_t *inhdr;
        uint8_t *bytes;
        uint8_t *p;
        NTSTATUS status;
@@ -500,14 +443,13 @@ static void cli_session_setup_guest_done(struct tevent_req *subreq)
                return;
        }
 
-       inbuf = (char *)in;
+       inhdr = in + NBT_HDR_SIZE;
        p = bytes;
 
-       cli_state_set_uid(state->cli, SVAL(inbuf, smb_uid));
-       cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
+       cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
 
        status = smb_bytes_talloc_string(cli,
-                                       inbuf,
+                                       inhdr,
                                        &cli->server_os,
                                        p,
                                        bytes+num_bytes-p,
@@ -520,7 +462,7 @@ static void cli_session_setup_guest_done(struct tevent_req *subreq)
        p += ret;
 
        status = smb_bytes_talloc_string(cli,
-                                       inbuf,
+                                       inhdr,
                                        &cli->server_type,
                                        p,
                                        bytes+num_bytes-p,
@@ -533,7 +475,7 @@ static void cli_session_setup_guest_done(struct tevent_req *subreq)
        p += ret;
 
        status = smb_bytes_talloc_string(cli,
-                                       inbuf,
+                                       inhdr,
                                        &cli->server_domain,
                                        p,
                                        bytes+num_bytes-p,
@@ -558,44 +500,6 @@ NTSTATUS cli_session_setup_guest_recv(struct tevent_req *req)
        return tevent_req_simple_recv_ntstatus(req);
 }
 
-static NTSTATUS cli_session_setup_guest(struct cli_state *cli)
-{
-       TALLOC_CTX *frame = talloc_stackframe();
-       struct event_context *ev;
-       struct tevent_req *req;
-       NTSTATUS status = NT_STATUS_OK;
-
-       if (cli_has_async_calls(cli)) {
-               /*
-                * Can't use sync call while an async call is in flight
-                */
-               status = NT_STATUS_INVALID_PARAMETER;
-               goto fail;
-       }
-
-       ev = event_context_init(frame);
-       if (ev == NULL) {
-               status = NT_STATUS_NO_MEMORY;
-               goto fail;
-       }
-
-       req = cli_session_setup_guest_send(frame, ev, cli);
-       if (req == NULL) {
-               status = NT_STATUS_NO_MEMORY;
-               goto fail;
-       }
-
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
-               goto fail;
-       }
-
-       status = cli_session_setup_guest_recv(req);
- fail:
-       TALLOC_FREE(frame);
-       return status;
-}
-
 /****************************************************************************
  Do a NT1 plaintext session setup.
 ****************************************************************************/
@@ -635,7 +539,7 @@ static struct tevent_req *cli_session_setup_plain_send(
        SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
        SSVAL(vwv+3, 0, 2);
        SSVAL(vwv+4, 0, cli_state_get_vc_num(cli));
-       SIVAL(vwv+5, 0, cli_state_server_session_key(cli));
+       SIVAL(vwv+5, 0, smb1cli_conn_server_session_key(cli->conn));
        SSVAL(vwv+7, 0, 0);
        SSVAL(vwv+8, 0, 0);
        SSVAL(vwv+9, 0, 0);
@@ -643,18 +547,18 @@ static struct tevent_req *cli_session_setup_plain_send(
        SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli, 0));
 
        bytes = talloc_array(state, uint8_t, 0);
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), pass, strlen(pass)+1,
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), pass, strlen(pass)+1,
                                   &passlen);
        if (tevent_req_nomem(bytes, req)) {
                return tevent_req_post(req, ev);
        }
-       SSVAL(vwv + (cli_ucs2(cli) ? 8 : 7), 0, passlen);
+       SSVAL(vwv + (smbXcli_conn_use_unicode(cli->conn) ? 8 : 7), 0, passlen);
 
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
                                   user, strlen(user)+1, NULL);
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
                                   workgroup, strlen(workgroup)+1, NULL);
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
                                   "Unix", 5, NULL);
 
        version = talloc_asprintf(talloc_tos(), "Samba %s",
@@ -662,7 +566,7 @@ static struct tevent_req *cli_session_setup_plain_send(
        if (tevent_req_nomem(version, req)){
                return tevent_req_post(req, ev);
        }
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
                                   version, strlen(version)+1, NULL);
        TALLOC_FREE(version);
 
@@ -688,7 +592,7 @@ static void cli_session_setup_plain_done(struct tevent_req *subreq)
        struct cli_state *cli = state->cli;
        uint32_t num_bytes;
        uint8_t *in;
-       char *inbuf;
+       uint8_t *inhdr;
        uint8_t *bytes;
        uint8_t *p;
        NTSTATUS status;
@@ -703,14 +607,13 @@ static void cli_session_setup_plain_done(struct tevent_req *subreq)
                return;
        }
 
-       inbuf = (char *)in;
+       inhdr = in + NBT_HDR_SIZE;
        p = bytes;
 
-       cli_state_set_uid(state->cli, SVAL(inbuf, smb_uid));
-       cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
+       cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
 
        status = smb_bytes_talloc_string(cli,
-                                       inbuf,
+                                       inhdr,
                                        &cli->server_os,
                                        p,
                                        bytes+num_bytes-p,
@@ -723,7 +626,7 @@ static void cli_session_setup_plain_done(struct tevent_req *subreq)
        p += ret;
 
        status = smb_bytes_talloc_string(cli,
-                                       inbuf,
+                                       inhdr,
                                        &cli->server_type,
                                        p,
                                        bytes+num_bytes-p,
@@ -736,7 +639,7 @@ static void cli_session_setup_plain_done(struct tevent_req *subreq)
        p += ret;
 
        status = smb_bytes_talloc_string(cli,
-                                       inbuf,
+                                       inhdr,
                                        &cli->server_domain,
                                        p,
                                        bytes+num_bytes-p,
@@ -761,40 +664,6 @@ static NTSTATUS cli_session_setup_plain_recv(struct tevent_req *req)
        return tevent_req_simple_recv_ntstatus(req);
 }
 
-static NTSTATUS cli_session_setup_plain(struct cli_state *cli,
-                                       const char *user, const char *pass,
-                                       const char *workgroup)
-{
-       TALLOC_CTX *frame = talloc_stackframe();
-       struct event_context *ev;
-       struct tevent_req *req;
-       NTSTATUS status = NT_STATUS_NO_MEMORY;
-
-       if (cli_has_async_calls(cli)) {
-               /*
-                * Can't use sync call while an async call is in flight
-                */
-               status = NT_STATUS_INVALID_PARAMETER;
-               goto fail;
-       }
-       ev = event_context_init(frame);
-       if (ev == NULL) {
-               goto fail;
-       }
-       req = cli_session_setup_plain_send(frame, ev, cli, user, pass,
-                                          workgroup);
-       if (req == NULL) {
-               goto fail;
-       }
-       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
-               goto fail;
-       }
-       status = cli_session_setup_plain_recv(req);
- fail:
-       TALLOC_FREE(frame);
-       return status;
-}
-
 /****************************************************************************
    do a NT1 NTLM/LM encrypted session setup - for when extended security
    is not negotiated.
@@ -847,11 +716,9 @@ static struct tevent_req *cli_session_setup_nt1_send(
                        DATA_BLOB server_chal;
                        DATA_BLOB names_blob;
 
-                       server_chal = data_blob(cli->secblob.data,
-                                               MIN(cli->secblob.length, 8));
-                       if (tevent_req_nomem(server_chal.data, req)) {
-                               return tevent_req_post(req, ev);
-                       }
+                       server_chal =
+                               data_blob_const(smb1cli_conn_server_challenge(cli->conn),
+                                               8);
 
                        /*
                         * note that the 'workgroup' here is a best
@@ -871,13 +738,11 @@ static struct tevent_req *cli_session_setup_nt1_send(
                                              &lm_response, &nt_response,
                                              NULL, &session_key)) {
                                data_blob_free(&names_blob);
-                               data_blob_free(&server_chal);
                                tevent_req_nterror(
                                        req, NT_STATUS_ACCESS_DENIED);
                                return tevent_req_post(req, ev);
                        }
                        data_blob_free(&names_blob);
-                       data_blob_free(&server_chal);
 
                } else {
                        uchar nt_hash[16];
@@ -891,7 +756,7 @@ static struct tevent_req *cli_session_setup_nt1_send(
                                return tevent_req_post(req, ev);
                        }
 
-                       SMBNTencrypt(pass, cli->secblob.data,
+                       SMBNTencrypt(pass, smb1cli_conn_server_challenge(cli->conn),
                                     nt_response.data);
 #endif
                        /* non encrypted password supplied. Ignore ntpass. */
@@ -902,7 +767,8 @@ static struct tevent_req *cli_session_setup_nt1_send(
                                        return tevent_req_post(req, ev);
                                }
 
-                               if (!SMBencrypt(pass,cli->secblob.data,
+                               if (!SMBencrypt(pass,
+                                               smb1cli_conn_server_challenge(cli->conn),
                                                lm_response.data)) {
                                        /*
                                         * Oops, the LM response is
@@ -980,7 +846,7 @@ static struct tevent_req *cli_session_setup_nt1_send(
        SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
        SSVAL(vwv+3, 0, 2);
        SSVAL(vwv+4, 0, cli_state_get_vc_num(cli));
-       SIVAL(vwv+5, 0, cli_state_server_session_key(cli));
+       SIVAL(vwv+5, 0, smb1cli_conn_server_session_key(cli->conn));
        SSVAL(vwv+7, 0, lm_response.length);
        SSVAL(vwv+8, 0, nt_response.length);
        SSVAL(vwv+9, 0, 0);
@@ -1002,7 +868,7 @@ static struct tevent_req *cli_session_setup_nt1_send(
        data_blob_free(&lm_response);
        data_blob_free(&nt_response);
 
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
                                   user, strlen(user)+1, NULL);
 
        /*
@@ -1012,13 +878,13 @@ static struct tevent_req *cli_session_setup_nt1_send(
        if (tevent_req_nomem(workgroup_upper, req)) {
                return tevent_req_post(req, ev);
        }
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
                                   workgroup_upper, strlen(workgroup_upper)+1,
                                   NULL);
        TALLOC_FREE(workgroup_upper);
 
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Unix", 5, NULL);
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Samba", 6, NULL);
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Unix", 5, NULL);
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Samba", 6, NULL);
        if (tevent_req_nomem(bytes, req)) {
                return tevent_req_post(req, ev);
        }
@@ -1041,7 +907,7 @@ static void cli_session_setup_nt1_done(struct tevent_req *subreq)
        struct cli_state *cli = state->cli;
        uint32_t num_bytes;
        uint8_t *in;
-       char *inbuf;
+       uint8_t *inhdr;
        uint8_t *bytes;
        uint8_t *p;
        NTSTATUS status;
@@ -1057,14 +923,13 @@ static void cli_session_setup_nt1_done(struct tevent_req *subreq)
                return;
        }
 
-       inbuf = (char *)in;
+       inhdr = in + NBT_HDR_SIZE;
        p = bytes;
 
-       cli_state_set_uid(state->cli, SVAL(inbuf, smb_uid));
-       cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
+       cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
 
        status = smb_bytes_talloc_string(cli,
-                                       inbuf,
+                                       inhdr,
                                        &cli->server_os,
                                        p,
                                        bytes+num_bytes-p,
@@ -1076,7 +941,7 @@ static void cli_session_setup_nt1_done(struct tevent_req *subreq)
        p += ret;
 
        status = smb_bytes_talloc_string(cli,
-                                       inbuf,
+                                       inhdr,
                                        &cli->server_type,
                                        p,
                                        bytes+num_bytes-p,
@@ -1088,7 +953,7 @@ static void cli_session_setup_nt1_done(struct tevent_req *subreq)
        p += ret;
 
        status = smb_bytes_talloc_string(cli,
-                                       inbuf,
+                                       inhdr,
                                        &cli->server_domain,
                                        p,
                                        bytes+num_bytes-p,
@@ -1103,14 +968,19 @@ static void cli_session_setup_nt1_done(struct tevent_req *subreq)
        if (tevent_req_nterror(req, status)) {
                return;
        }
-       if (cli_simple_set_signing(cli, state->session_key, state->response)
-           && !cli_check_sign_mac(cli, (char *)in, 1)) {
+       if (smb1cli_conn_activate_signing(cli->conn, state->session_key, state->response)
+           && !smb1cli_conn_check_signing(cli->conn, (uint8_t *)in, 1)) {
                tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
                return;
        }
        if (state->session_key.data) {
-               /* Have plaintext orginal */
-               cli_set_session_key(cli, state->session_key);
+               struct smbXcli_session *session = state->cli->smb1.session;
+
+               status = smb1cli_session_set_session_key(session,
+                               state->session_key);
+               if (tevent_req_nterror(req, status)) {
+                       return;
+               }
        }
        tevent_req_done(req);
 }
@@ -1120,41 +990,6 @@ static NTSTATUS cli_session_setup_nt1_recv(struct tevent_req *req)
        return tevent_req_simple_recv_ntstatus(req);
 }
 
-static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
-                                     const char *pass, size_t passlen,
-                                     const char *ntpass, size_t ntpasslen,
-                                     const char *workgroup)
-{
-       TALLOC_CTX *frame = talloc_stackframe();
-       struct event_context *ev;
-       struct tevent_req *req;
-       NTSTATUS status = NT_STATUS_NO_MEMORY;
-
-       if (cli_has_async_calls(cli)) {
-               /*
-                * Can't use sync call while an async call is in flight
-                */
-               status = NT_STATUS_INVALID_PARAMETER;
-               goto fail;
-       }
-       ev = event_context_init(frame);
-       if (ev == NULL) {
-               goto fail;
-       }
-       req = cli_session_setup_nt1_send(frame, ev, cli, user, pass, passlen,
-                                        ntpass, ntpasslen, workgroup);
-       if (req == NULL) {
-               goto fail;
-       }
-       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
-               goto fail;
-       }
-       status = cli_session_setup_nt1_recv(req);
- fail:
-       TALLOC_FREE(frame);
-       return status;
-}
-
 /* The following is calculated from :
  * (smb_size-4) = 35
  * (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() )
@@ -1172,8 +1007,11 @@ struct cli_sesssetup_blob_state {
        uint16_t vwv[12];
        uint8_t *buf;
 
+       DATA_BLOB smb2_blob;
+       struct iovec *recv_iov;
+
        NTSTATUS status;
-       char *inbuf;
+       uint8_t *inbuf;
        DATA_BLOB ret_blob;
 };
 
@@ -1199,8 +1037,12 @@ static struct tevent_req *cli_sesssetup_blob_send(TALLOC_CTX *mem_ctx,
        state->blob = blob;
        state->cli = cli;
 
-       usable_space = cli_state_available_size(cli,
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               usable_space = UINT16_MAX;
+       } else {
+               usable_space = cli_state_available_size(cli,
                                BASE_SESSSETUP_BLOB_PACKET_SIZE);
+       }
 
        if (usable_space == 0) {
                DEBUG(1, ("cli_session_setup_blob: cli->max_xmit too small "
@@ -1225,6 +1067,32 @@ static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
        struct tevent_req *subreq;
        uint16_t thistime;
 
+       thistime = MIN(state->blob.length, state->max_blob_size);
+
+       if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+
+               state->smb2_blob.data = state->blob.data;
+               state->smb2_blob.length = thistime;
+
+               state->blob.data += thistime;
+               state->blob.length -= thistime;
+
+               subreq = smb2cli_session_setup_send(state, state->ev,
+                                                   state->cli->conn,
+                                                   state->cli->timeout,
+                                                   state->cli->smb2.session,
+                                                   0, /* in_flags */
+                                                   SMB2_CAP_DFS, /* in_capabilities */
+                                                   0, /* in_channel */
+                                                   0, /* in_previous_session_id */
+                                                   &state->smb2_blob);
+               if (subreq == NULL) {
+                       return false;
+               }
+               *psubreq = subreq;
+               return true;
+       }
+
        SCVAL(state->vwv+0, 0, 0xFF);
        SCVAL(state->vwv+0, 1, 0);
        SSVAL(state->vwv+1, 0, 0);
@@ -1233,7 +1101,6 @@ static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
        SSVAL(state->vwv+4, 0, 1);
        SIVAL(state->vwv+5, 0, 0);
 
-       thistime = MIN(state->blob.length, state->max_blob_size);
        SSVAL(state->vwv+7, 0, thistime);
 
        SSVAL(state->vwv+8, 0, 0);
@@ -1249,9 +1116,9 @@ static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
        state->blob.data += thistime;
        state->blob.length -= thistime;
 
-       state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli),
+       state->buf = smb_bytes_push_str(state->buf, smbXcli_conn_use_unicode(state->cli->conn),
                                        "Unix", 5, NULL);
-       state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli),
+       state->buf = smb_bytes_push_str(state->buf, smbXcli_conn_use_unicode(state->cli->conn),
                                        "Samba", 6, NULL);
        if (state->buf == NULL) {
                return false;
@@ -1280,11 +1147,19 @@ static void cli_sesssetup_blob_done(struct tevent_req *subreq)
        NTSTATUS status;
        uint8_t *p;
        uint16_t blob_length;
-       uint8_t *inbuf;
+       uint8_t *in;
+       uint8_t *inhdr;
        ssize_t ret;
 
-       status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv,
-                             &num_bytes, &bytes);
+       if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+               status = smb2cli_session_setup_recv(subreq, state,
+                                                   &state->recv_iov,
+                                                   &state->ret_blob);
+       } else {
+               status = cli_smb_recv(subreq, state, &in, 4, &wct, &vwv,
+                                     &num_bytes, &bytes);
+               TALLOC_FREE(state->buf);
+       }
        TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)
            && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
@@ -1293,11 +1168,14 @@ static void cli_sesssetup_blob_done(struct tevent_req *subreq)
        }
 
        state->status = status;
-       TALLOC_FREE(state->buf);
 
-       state->inbuf = (char *)inbuf;
-       cli_state_set_uid(state->cli, SVAL(inbuf, smb_uid));
-       cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
+       if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+               goto next;
+       }
+
+       state->inbuf = in;
+       inhdr = in + NBT_HDR_SIZE;
+       cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
 
        blob_length = SVAL(vwv+3, 0);
        if (blob_length > num_bytes) {
@@ -1309,7 +1187,7 @@ static void cli_sesssetup_blob_done(struct tevent_req *subreq)
        p = bytes + blob_length;
 
        status = smb_bytes_talloc_string(cli,
-                                       (char *)inbuf,
+                                       inhdr,
                                        &cli->server_os,
                                        p,
                                        bytes+num_bytes-p,
@@ -1322,7 +1200,7 @@ static void cli_sesssetup_blob_done(struct tevent_req *subreq)
        p += ret;
 
        status = smb_bytes_talloc_string(cli,
-                                       (char *)inbuf,
+                                       inhdr,
                                        &cli->server_type,
                                        p,
                                        bytes+num_bytes-p,
@@ -1335,7 +1213,7 @@ static void cli_sesssetup_blob_done(struct tevent_req *subreq)
        p += ret;
 
        status = smb_bytes_talloc_string(cli,
-                                       (char *)inbuf,
+                                       inhdr,
                                        &cli->server_domain,
                                        p,
                                        bytes+num_bytes-p,
@@ -1347,6 +1225,7 @@ static void cli_sesssetup_blob_done(struct tevent_req *subreq)
        }
        p += ret;
 
+next:
        if (state->blob.length != 0) {
                /*
                 * More to send
@@ -1364,25 +1243,32 @@ static void cli_sesssetup_blob_done(struct tevent_req *subreq)
 static NTSTATUS cli_sesssetup_blob_recv(struct tevent_req *req,
                                        TALLOC_CTX *mem_ctx,
                                        DATA_BLOB *pblob,
-                                       char **pinbuf)
+                                       uint8_t **pinbuf,
+                                       struct iovec **precv_iov)
 {
        struct cli_sesssetup_blob_state *state = tevent_req_data(
                req, struct cli_sesssetup_blob_state);
        NTSTATUS status;
-       char *inbuf;
+       uint8_t *inbuf;
+       struct iovec *recv_iov;
 
        if (tevent_req_is_nterror(req, &status)) {
+               TALLOC_FREE(state->cli->smb2.session);
                cli_state_set_uid(state->cli, UID_FIELD_INVALID);
                return status;
        }
 
        inbuf = talloc_move(mem_ctx, &state->inbuf);
+       recv_iov = talloc_move(mem_ctx, &state->recv_iov);
        if (pblob != NULL) {
                *pblob = state->ret_blob;
        }
        if (pinbuf != NULL) {
                *pinbuf = inbuf;
        }
+       if (precv_iov != NULL) {
+               *precv_iov = recv_iov;
+       }
         /* could be NT_STATUS_MORE_PROCESSING_REQUIRED */
        return state->status;
 }
@@ -1433,7 +1319,7 @@ static struct tevent_req *cli_session_setup_kerberos_send(
         * we have to acquire a ticket. To be fixed later :-)
         */
        rc = spnego_gen_krb5_negTokenInit(state, principal, 0, &state->negTokenTarg,
-                                    &state->session_key_krb5, 0, NULL);
+                                    &state->session_key_krb5, 0, NULL, NULL);
        if (rc) {
                DEBUG(1, ("cli_session_setup_kerberos: "
                          "spnego_gen_krb5_negTokenInit failed: %s\n",
@@ -1448,6 +1334,14 @@ static struct tevent_req *cli_session_setup_kerberos_send(
                  state->negTokenTarg.length);
 #endif
 
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               state->cli->smb2.session = smbXcli_session_create(cli,
+                                                                 cli->conn);
+               if (tevent_req_nomem(state->cli->smb2.session, req)) {
+                       return tevent_req_post(req, ev);
+               }
+       }
+
        subreq = cli_sesssetup_blob_send(state, ev, cli, state->negTokenTarg);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
@@ -1462,26 +1356,43 @@ static void cli_session_setup_kerberos_done(struct tevent_req *subreq)
                subreq, struct tevent_req);
        struct cli_session_setup_kerberos_state *state = tevent_req_data(
                req, struct cli_session_setup_kerberos_state);
-       char *inbuf = NULL;
+       uint8_t *inbuf = NULL;
+       struct iovec *recv_iov = NULL;
        NTSTATUS status;
 
-       status = cli_sesssetup_blob_recv(subreq, talloc_tos(), NULL, &inbuf);
+       status = cli_sesssetup_blob_recv(subreq, state,
+                                        NULL, &inbuf, &recv_iov);
+       TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
-               TALLOC_FREE(subreq);
                tevent_req_nterror(req, status);
                return;
        }
 
-       cli_set_session_key(state->cli, state->session_key_krb5);
+       if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+               struct smbXcli_session *session = state->cli->smb2.session;
+               status = smb2cli_session_set_session_key(session,
+                                               state->session_key_krb5,
+                                               recv_iov);
+               if (tevent_req_nterror(req, status)) {
+                       return;
+               }
+       } else {
+               struct smbXcli_session *session = state->cli->smb1.session;
 
-       if (cli_simple_set_signing(state->cli, state->session_key_krb5,
-                                  data_blob_null)
-           && !cli_check_sign_mac(state->cli, inbuf, 1)) {
-               TALLOC_FREE(subreq);
-               tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
-               return;
+               status = smb1cli_session_set_session_key(session,
+                                                        state->session_key_krb5);
+               if (tevent_req_nterror(req, status)) {
+                       return;
+               }
+
+               if (smb1cli_conn_activate_signing(state->cli->conn, state->session_key_krb5,
+                                          data_blob_null)
+                   && !smb1cli_conn_check_signing(state->cli->conn, inbuf, 1)) {
+                       tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+                       return;
+               }
        }
-       TALLOC_FREE(subreq);
+
        tevent_req_done(req);
 }
 
@@ -1497,33 +1408,6 @@ static ADS_STATUS cli_session_setup_kerberos_recv(struct tevent_req *req)
        return state->ads_status;
 }
 
-static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli,
-                                            const char *principal)
-{
-       struct tevent_context *ev;
-       struct tevent_req *req;
-       ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
-
-       if (cli_has_async_calls(cli)) {
-               return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
-       }
-       ev = tevent_context_init(talloc_tos());
-       if (ev == NULL) {
-               goto fail;
-       }
-       req = cli_session_setup_kerberos_send(ev, ev, cli, principal);
-       if (req == NULL) {
-               goto fail;
-       }
-       if (!tevent_req_poll(req, ev)) {
-               status = ADS_ERROR_SYSTEM(errno);
-               goto fail;
-       }
-       status = cli_session_setup_kerberos_recv(req);
-fail:
-       TALLOC_FREE(ev);
-       return status;
-}
 #endif /* HAVE_KRB5 */
 
 /****************************************************************************
@@ -1594,7 +1478,11 @@ static struct tevent_req *cli_session_setup_ntlmssp_send(
        if (!NT_STATUS_IS_OK(status)) {
                goto fail;
        }
-       status = ntlmssp_set_password(state->ntlmssp_state, pass);
+       if (cli->pw_nt_hash) {
+               status = ntlmssp_set_password_hash(state->ntlmssp_state, pass);
+       } else {
+               status = ntlmssp_set_password(state->ntlmssp_state, pass);
+       }
        if (!NT_STATUS_IS_OK(status)) {
                goto fail;
        }
@@ -1607,6 +1495,14 @@ static struct tevent_req *cli_session_setup_ntlmssp_send(
        state->blob_out = spnego_gen_negTokenInit(state, OIDs_ntlm, &blob_out, NULL);
        data_blob_free(&blob_out);
 
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               state->cli->smb2.session = smbXcli_session_create(cli,
+                                                                 cli->conn);
+               if (tevent_req_nomem(state->cli->smb2.session, req)) {
+                       return tevent_req_post(req, ev);
+               }
+       }
+
        subreq = cli_sesssetup_blob_send(state, ev, cli, state->blob_out);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
@@ -1625,12 +1521,13 @@ static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq)
        struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
                req, struct cli_session_setup_ntlmssp_state);
        DATA_BLOB blob_in, msg_in, blob_out;
-       char *inbuf = NULL;
+       uint8_t *inbuf = NULL;
+       struct iovec *recv_iov = NULL;
        bool parse_ret;
        NTSTATUS status;
 
        status = cli_sesssetup_blob_recv(subreq, talloc_tos(), &blob_in,
-                                        &inbuf);
+                                        &inbuf, &recv_iov);
        TALLOC_FREE(subreq);
        data_blob_free(&state->blob_out);
 
@@ -1640,23 +1537,52 @@ static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq)
                        state->cli->server_domain = talloc_strdup(state->cli,
                                                state->ntlmssp_state->server.netbios_domain);
                        if (state->cli->server_domain == NULL) {
-                               TALLOC_FREE(subreq);
                                tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
                                return;
                        }
                }
-               cli_set_session_key(
-                       state->cli, state->ntlmssp_state->session_key);
-
-               if (cli_simple_set_signing(
-                           state->cli, state->ntlmssp_state->session_key,
-                           data_blob_null)
-                   && !cli_check_sign_mac(state->cli, inbuf, 1)) {
-                       TALLOC_FREE(subreq);
-                       tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
-                       return;
+
+               if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+                       struct smbXcli_session *session = state->cli->smb2.session;
+
+                       if (ntlmssp_is_anonymous(state->ntlmssp_state)) {
+                               /*
+                                * Windows server does not set the
+                                * SMB2_SESSION_FLAG_IS_GUEST nor
+                                * SMB2_SESSION_FLAG_IS_NULL flag.
+                                *
+                                * This fix makes sure we do not try
+                                * to verify a signature on the final
+                                * session setup response.
+                                */
+                               TALLOC_FREE(state->ntlmssp_state);
+                               tevent_req_done(req);
+                               return;
+                       }
+
+                       status = smb2cli_session_set_session_key(session,
+                                               state->ntlmssp_state->session_key,
+                                               recv_iov);
+                       if (tevent_req_nterror(req, status)) {
+                               return;
+                       }
+               } else {
+                       struct smbXcli_session *session = state->cli->smb1.session;
+
+                       status = smb1cli_session_set_session_key(session,
+                                       state->ntlmssp_state->session_key);
+                       if (tevent_req_nterror(req, status)) {
+                               return;
+                       }
+
+                       if (smb1cli_conn_activate_signing(
+                                   state->cli->conn, state->ntlmssp_state->session_key,
+                                   data_blob_null)
+                           && !smb1cli_conn_check_signing(state->cli->conn, inbuf, 1)) {
+                               tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+                               return;
+                       }
                }
-               TALLOC_FREE(subreq);
                TALLOC_FREE(state->ntlmssp_state);
                tevent_req_done(req);
                return;
@@ -1699,14 +1625,12 @@ static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq)
 
        if (!NT_STATUS_IS_OK(status)
            && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-               TALLOC_FREE(subreq);
                TALLOC_FREE(state->ntlmssp_state);
                tevent_req_nterror(req, status);
                return;
        }
 
        state->blob_out = spnego_gen_auth(state, blob_out);
-       TALLOC_FREE(subreq);
        if (tevent_req_nomem(state->blob_out.data, req)) {
                return;
        }
@@ -1732,33 +1656,64 @@ static NTSTATUS cli_session_setup_ntlmssp_recv(struct tevent_req *req)
        return NT_STATUS_OK;
 }
 
-static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli,
-                                         const char *user,
-                                         const char *pass,
-                                         const char *domain)
+#ifdef HAVE_KRB5
+
+static char *cli_session_setup_get_principal(
+       TALLOC_CTX *mem_ctx, const char *spnego_principal,
+       const char *remote_name, const char *dest_realm)
 {
-       struct tevent_context *ev;
-       struct tevent_req *req;
-       NTSTATUS status = NT_STATUS_NO_MEMORY;
+       char *principal = NULL;
 
-       if (cli_has_async_calls(cli)) {
-               return NT_STATUS_INVALID_PARAMETER;
+       if (!lp_client_use_spnego_principal() ||
+           strequal(principal, ADS_IGNORE_PRINCIPAL)) {
+               spnego_principal = NULL;
        }
-       ev = tevent_context_init(talloc_tos());
-       if (ev == NULL) {
-               goto fail;
+       if (spnego_principal != NULL) {
+               DEBUG(3, ("cli_session_setup_spnego: using spnego provided "
+                         "principal %s\n", spnego_principal));
+               return talloc_strdup(mem_ctx, spnego_principal);
        }
-       req = cli_session_setup_ntlmssp_send(ev, ev, cli, user, pass, domain);
-       if (req == NULL) {
-               goto fail;
+       if (is_ipaddress(remote_name) ||
+           strequal(remote_name, STAR_SMBSERVER)) {
+               return NULL;
        }
-       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
-               goto fail;
+
+       DEBUG(3, ("cli_session_setup_spnego: using target "
+                 "hostname not SPNEGO principal\n"));
+
+       if (dest_realm) {
+               char *realm = strupper_talloc(talloc_tos(), dest_realm);
+               if (realm == NULL) {
+                       return NULL;
+               }
+               principal = talloc_asprintf(talloc_tos(), "cifs/%s@%s",
+                                           remote_name, realm);
+               TALLOC_FREE(realm);
+       } else {
+               principal = kerberos_get_principal_from_service_hostname(
+                       talloc_tos(), "cifs", remote_name, lp_realm());
        }
-       status = cli_session_setup_ntlmssp_recv(req);
-fail:
-       TALLOC_FREE(ev);
-       return status;
+       DEBUG(3, ("cli_session_setup_spnego: guessed server principal=%s\n",
+                 principal ? principal : "<null>"));
+
+       return principal;
+}
+#endif
+
+static char *cli_session_setup_get_account(TALLOC_CTX *mem_ctx,
+                                          const char *principal)
+{
+       char *account, *p;
+
+       account = talloc_strdup(mem_ctx, principal);
+       if (account == NULL) {
+               return NULL;
+       }
+       p = strchr_m(account, '@');
+       if (p != NULL) {
+               *p = '\0';
+       }
+       return account;
 }
 
 /****************************************************************************
@@ -1768,24 +1723,60 @@ fail:
  dest_realm: The realm we're connecting to, if NULL we use our default realm.
 ****************************************************************************/
 
-static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli,
-                             const char *user,
-                             const char *pass,
-                             const char *user_domain,
-                             const char * dest_realm)
+struct cli_session_setup_spnego_state {
+       struct tevent_context *ev;
+       struct cli_state *cli;
+       const char *user;
+       const char *account;
+       const char *pass;
+       const char *user_domain;
+       const char *dest_realm;
+       ADS_STATUS result;
+};
+
+#ifdef HAVE_KRB5
+static void cli_session_setup_spnego_done_krb(struct tevent_req *subreq);
+#endif
+
+static void cli_session_setup_spnego_done_ntlmssp(struct tevent_req *subreq);
+
+static struct tevent_req *cli_session_setup_spnego_send(
+       TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
+       const char *user, const char *pass, const char *user_domain,
+       const char *dest_realm)
 {
+       struct tevent_req *req, *subreq;
+       struct cli_session_setup_spnego_state *state;
        char *principal = NULL;
        char *OIDs[ASN1_MAX_OIDS];
        int i;
-       DATA_BLOB blob;
-       const char *p = NULL;
-       char *account = NULL;
+       const DATA_BLOB *server_blob;
        NTSTATUS status;
 
-       DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)cli->secblob.length));
+       req = tevent_req_create(mem_ctx, &state,
+                               struct cli_session_setup_spnego_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->ev = ev;
+       state->cli = cli;
+       state->user = user;
+       state->pass = pass;
+       state->user_domain = user_domain;
+       state->dest_realm = dest_realm;
+
+       state->account = cli_session_setup_get_account(state, user);
+       if (tevent_req_nomem(state->account, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       server_blob = smbXcli_conn_server_gss_blob(cli->conn);
+
+       DEBUG(3,("Doing spnego session setup (blob length=%lu)\n",
+                (unsigned long)server_blob->length));
 
        /* the server might not even do spnego */
-       if (cli->secblob.length == 0) {
+       if (server_blob->length == 0) {
                DEBUG(3,("server didn't supply a full spnego negprot\n"));
                goto ntlmssp;
        }
@@ -1794,18 +1785,17 @@ static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli,
        file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
 #endif
 
-       blob = data_blob(cli->secblob.data, cli->secblob.length);
-
        /* The server sent us the first part of the SPNEGO exchange in the
         * negprot reply. It is WRONG to depend on the principal sent in the
         * negprot reply, but right now we do it. If we don't receive one,
         * we try to best guess, then fall back to NTLM.  */
-       if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &principal, NULL) ||
+       if (!spnego_parse_negTokenInit(state, *server_blob, OIDs,
+                                      &principal, NULL) ||
                        OIDs[0] == NULL) {
-               data_blob_free(&blob);
-               return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               state->result = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               tevent_req_done(req);
+               return tevent_req_post(req, ev);
        }
-       data_blob_free(&blob);
 
        /* make sure the server understands kerberos */
        for (i=0;OIDs[i];i++) {
@@ -1824,17 +1814,18 @@ static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli,
 
        status = cli_set_username(cli, user);
        if (!NT_STATUS_IS_OK(status)) {
-               TALLOC_FREE(principal);
-               return ADS_ERROR_NT(status);
+               state->result = ADS_ERROR_NT(status);
+               tevent_req_done(req);
+               return tevent_req_post(req, ev);
        }
 
 #ifdef HAVE_KRB5
        /* If password is set we reauthenticate to kerberos server
         * and do not store results */
 
-       if (cli->got_kerberos_mechanism && cli->use_kerberos) {
-               ADS_STATUS rc;
-               const char *remote_name = cli_state_remote_name(cli);
+       if (user && *user && cli->got_kerberos_mechanism && cli->use_kerberos) {
+               const char *remote_name = smbXcli_conn_remote_name(cli->conn);
+               char *tmp;
 
                if (pass && *pass) {
                        int ret;
@@ -1847,124 +1838,136 @@ static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli,
                                DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
                                if (cli->fallback_after_kerberos)
                                        goto ntlmssp;
-                               return ADS_ERROR_KRB5(ret);
+                               state->result = ADS_ERROR_KRB5(ret);
+                               tevent_req_done(req);
+                               return tevent_req_post(req, ev);
                        }
                }
 
-               /* We may not be allowed to use the server-supplied SPNEGO principal, or it may not have been supplied to us
-                */
-               if (!lp_client_use_spnego_principal() || strequal(principal, ADS_IGNORE_PRINCIPAL)) {
-                       TALLOC_FREE(principal);
-               }
-
-               if (principal == NULL &&
-                       !is_ipaddress(remote_name) &&
-                       !strequal(STAR_SMBSERVER,
-                                 remote_name)) {
-                       char *realm = NULL;
-                       char *host = NULL;
-                       DEBUG(3,("cli_session_setup_spnego: using target "
-                                "hostname not SPNEGO principal\n"));
-
-                       host = strchr_m(remote_name, '.');
-                       if (dest_realm) {
-                               realm = SMB_STRDUP(dest_realm);
-                               if (!realm) {
-                                       return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
-                               }
-                               strupper_m(realm);
-                       } else {
-                               if (host) {
-                                       /* DNS name. */
-                                       realm = kerberos_get_realm_from_hostname(remote_name);
-                               } else {
-                                       /* NetBIOS name - use our realm. */
-                                       realm = kerberos_get_default_realm_from_ccache();
-                               }
-                       }
-
-                       if (realm == NULL || *realm == '\0') {
-                               realm = SMB_STRDUP(lp_realm());
-                               if (!realm) {
-                                       return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
-                               }
-                               strupper_m(realm);
-                               DEBUG(3,("cli_session_setup_spnego: cannot "
-                                       "get realm from dest_realm %s, "
-                                       "desthost %s. Using default "
-                                       "smb.conf realm %s\n",
-                                       dest_realm ? dest_realm : "<null>",
-                                       remote_name,
-                                       realm));
-                       }
-
-                       principal = talloc_asprintf(talloc_tos(),
-                                                   "cifs/%s@%s",
-                                                   remote_name,
-                                                   realm);
-                       if (!principal) {
-                               SAFE_FREE(realm);
-                               return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
-                       }
-                       DEBUG(3,("cli_session_setup_spnego: guessed "
-                               "server principal=%s\n",
-                               principal ? principal : "<null>"));
-
-                       SAFE_FREE(realm);
-               }
+               tmp = cli_session_setup_get_principal(
+                       talloc_tos(), principal, remote_name, dest_realm);
+               TALLOC_FREE(principal);
+               principal = tmp;
 
                if (principal) {
-                       rc = cli_session_setup_kerberos(cli, principal);
-                       if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) {
-                               TALLOC_FREE(principal);
-                               return rc;
+                       subreq = cli_session_setup_kerberos_send(
+                               state, ev, cli, principal);
+                       if (tevent_req_nomem(subreq, req)) {
+                               return tevent_req_post(req, ev);
                        }
+                       tevent_req_set_callback(
+                               subreq, cli_session_setup_spnego_done_krb,
+                               req);
+                       return req;
                }
        }
 #endif
 
-       TALLOC_FREE(principal);
-
 ntlmssp:
-
-       account = talloc_strdup(talloc_tos(), user);
-       if (!account) {
-               return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+       subreq = cli_session_setup_ntlmssp_send(
+               state, ev, cli, state->account, pass, user_domain);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
        }
+       tevent_req_set_callback(
+               subreq, cli_session_setup_spnego_done_ntlmssp, req);
+       return req;
+}
+
+#ifdef HAVE_KRB5
+static void cli_session_setup_spnego_done_krb(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_session_setup_spnego_state *state = tevent_req_data(
+               req, struct cli_session_setup_spnego_state);
+
+       state->result = cli_session_setup_kerberos_recv(subreq);
+       TALLOC_FREE(subreq);
 
-       /* when falling back to ntlmssp while authenticating with a machine
-        * account strip off the realm - gd */
+       if (ADS_ERR_OK(state->result) ||
+           !state->cli->fallback_after_kerberos) {
+               tevent_req_done(req);
+               return;
+       }
 
-       if ((p = strchr_m(user, '@')) != NULL) {
-               account[PTR_DIFF(p,user)] = '\0';
+       subreq = cli_session_setup_ntlmssp_send(
+               state, state->ev, state->cli, state->account, state->pass,
+               state->user_domain);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
        }
+       tevent_req_set_callback(subreq, cli_session_setup_spnego_done_ntlmssp,
+                               req);
+}
+#endif
+
+static void cli_session_setup_spnego_done_ntlmssp(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_session_setup_spnego_state *state = tevent_req_data(
+               req, struct cli_session_setup_spnego_state);
+       NTSTATUS status;
+
+       status = cli_session_setup_ntlmssp_recv(subreq);
+       TALLOC_FREE(subreq);
+       state->result = ADS_ERROR_NT(status);
+       tevent_req_done(req);
+}
+
+static ADS_STATUS cli_session_setup_spnego_recv(struct tevent_req *req)
+{
+       struct cli_session_setup_spnego_state *state = tevent_req_data(
+               req, struct cli_session_setup_spnego_state);
 
-       return ADS_ERROR_NT(cli_session_setup_ntlmssp(cli, account, pass, user_domain));
+       return state->result;
 }
 
+struct cli_session_setup_state {
+       uint8_t dummy;
+};
+
+static void cli_session_setup_done_lanman2(struct tevent_req *subreq);
+static void cli_session_setup_done_spnego(struct tevent_req *subreq);
+static void cli_session_setup_done_guest(struct tevent_req *subreq);
+static void cli_session_setup_done_plain(struct tevent_req *subreq);
+static void cli_session_setup_done_nt1(struct tevent_req *subreq);
+
 /****************************************************************************
  Send a session setup. The username and workgroup is in UNIX character
  format and must be converted to DOS codepage format before sending. If the
  password is in plaintext, the same should be done.
 ****************************************************************************/
 
-NTSTATUS cli_session_setup(struct cli_state *cli,
-                          const char *user,
-                          const char *pass, int passlen,
-                          const char *ntpass, int ntpasslen,
-                          const char *workgroup)
+struct tevent_req *cli_session_setup_send(TALLOC_CTX *mem_ctx,
+                                         struct tevent_context *ev,
+                                         struct cli_state *cli,
+                                         const char *user,
+                                         const char *pass, int passlen,
+                                         const char *ntpass, int ntpasslen,
+                                         const char *workgroup)
 {
+       struct tevent_req *req, *subreq;
+       struct cli_session_setup_state *state;
        char *p;
        char *user2;
-       uint16_t sec_mode = cli_state_security_mode(cli);
+       uint16_t sec_mode = smb1cli_conn_server_security_mode(cli->conn);
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct cli_session_setup_state);
+       if (req == NULL) {
+               return NULL;
+       }
 
        if (user) {
-               user2 = talloc_strdup(talloc_tos(), user);
+               user2 = talloc_strdup(state, user);
        } else {
-               user2 = talloc_strdup(talloc_tos(), "");
+               user2 = talloc_strdup(state, "");
        }
        if (user2 == NULL) {
-               return NT_STATUS_NO_MEMORY;
+               tevent_req_oom(req);
+               return tevent_req_post(req, ev);
        }
 
        if (!workgroup) {
@@ -1976,25 +1979,16 @@ NTSTATUS cli_session_setup(struct cli_state *cli,
            (p=strchr_m(user2,*lp_winbind_separator()))) {
                *p = 0;
                user = p+1;
-               strupper_m(user2);
+               if (!strupper_m(user2)) {
+                       tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+                       return tevent_req_post(req, ev);
+               }
                workgroup = user2;
        }
 
-       if (cli_state_protocol(cli) < PROTOCOL_LANMAN1) {
-               /*
-                * Ensure cli->server_domain,
-                * cli->server_os and cli->server_type
-                * are valid pointers.
-                */
-               cli->server_domain = talloc_strdup(cli, "");
-               cli->server_os = talloc_strdup(cli, "");
-               cli->server_type = talloc_strdup(cli, "");
-               if (cli->server_domain == NULL ||
-                               cli->server_os == NULL ||
-                               cli->server_type == NULL) {
-                       return NT_STATUS_NO_MEMORY;
-               }
-               return NT_STATUS_OK;
+       if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_LANMAN1) {
+               tevent_req_done(req);
+               return tevent_req_post(req, ev);
        }
 
        /* now work out what sort of session setup we are going to
@@ -2003,74 +1997,236 @@ NTSTATUS cli_session_setup(struct cli_state *cli,
 
        /* if its an older server then we have to use the older request format */
 
-       if (cli_state_protocol(cli) < PROTOCOL_NT1) {
+       if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_NT1) {
                if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
                        DEBUG(1, ("Server requested LM password but 'client lanman auth = no'"
                                  " or 'client ntlmv2 auth = yes'\n"));
-                       return NT_STATUS_ACCESS_DENIED;
+                       tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+                       return tevent_req_post(req, ev);
                }
 
                if ((sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
                    !lp_client_plaintext_auth() && (*pass)) {
-                       DEBUG(1, ("Server requested LM password but 'client plaintext auth = no'"
+                       DEBUG(1, ("Server requested PLAINTEXT password but 'client plaintext auth = no'"
                                  " or 'client ntlmv2 auth = yes'\n"));
-                       return NT_STATUS_ACCESS_DENIED;
+                       tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+                       return tevent_req_post(req, ev);
+               }
+
+               subreq = cli_session_setup_lanman2_send(
+                       state, ev, cli, user, pass, passlen, workgroup);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
                }
+               tevent_req_set_callback(subreq, cli_session_setup_done_lanman2,
+                                       req);
+               return req;
+       }
+
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               const char *remote_realm = cli_state_remote_realm(cli);
 
-               return cli_session_setup_lanman2(cli, user, pass, passlen,
-                                                workgroup);
+               subreq = cli_session_setup_spnego_send(
+                       state, ev, cli, user, pass, workgroup, remote_realm);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
+               }
+               tevent_req_set_callback(subreq, cli_session_setup_done_spnego,
+                                       req);
+               return req;
        }
 
        /* if no user is supplied then we have to do an anonymous connection.
           passwords are ignored */
 
-       if (!user || !*user)
-               return cli_session_setup_guest(cli);
+       if (!user || !*user) {
+               subreq = cli_session_setup_guest_send(state, ev, cli);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
+               }
+               tevent_req_set_callback(subreq, cli_session_setup_done_guest,
+                                       req);
+               return req;
+       }
 
        /* if the server is share level then send a plaintext null
            password at this point. The password is sent in the tree
            connect */
 
-       if ((sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0)
-               return cli_session_setup_plain(cli, user, "", workgroup);
+       if ((sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0) {
+               subreq = cli_session_setup_plain_send(
+                       state, ev, cli, user, "", workgroup);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
+               }
+               tevent_req_set_callback(subreq, cli_session_setup_done_plain,
+                                       req);
+               return req;
+       }
 
        /* if the server doesn't support encryption then we have to use 
           plaintext. The second password is ignored */
 
        if ((sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
                if (!lp_client_plaintext_auth() && (*pass)) {
-                       DEBUG(1, ("Server requested LM password but 'client plaintext auth = no'"
+                       DEBUG(1, ("Server requested PLAINTEXT password but 'client plaintext auth = no'"
                                  " or 'client ntlmv2 auth = yes'\n"));
-                       return NT_STATUS_ACCESS_DENIED;
+                       tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+                       return tevent_req_post(req, ev);
+               }
+               subreq = cli_session_setup_plain_send(
+                       state, ev, cli, user, pass, workgroup);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
                }
-               return cli_session_setup_plain(cli, user, pass, workgroup);
+               tevent_req_set_callback(subreq, cli_session_setup_done_plain,
+                                       req);
+               return req;
        }
 
        /* if the server supports extended security then use SPNEGO */
 
-       if (cli_state_capabilities(cli) & CAP_EXTENDED_SECURITY) {
+       if (smb1cli_conn_capabilities(cli->conn) & CAP_EXTENDED_SECURITY) {
                const char *remote_realm = cli_state_remote_realm(cli);
-               ADS_STATUS status = cli_session_setup_spnego(cli, user, pass,
-                                                            workgroup,
-                                                            remote_realm);
-               if (!ADS_ERR_OK(status)) {
-                       DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status)));
-                       return ads_ntstatus(status);
+
+               subreq = cli_session_setup_spnego_send(
+                       state, ev, cli, user, pass, workgroup, remote_realm);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
                }
+               tevent_req_set_callback(subreq, cli_session_setup_done_spnego,
+                                       req);
+               return req;
        } else {
-               NTSTATUS status;
-
                /* otherwise do a NT1 style session setup */
-               status = cli_session_setup_nt1(cli, user, pass, passlen,
-                                              ntpass, ntpasslen, workgroup);
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(3,("cli_session_setup: NT1 session setup "
-                                "failed: %s\n", nt_errstr(status)));
-                       return status;
+
+               subreq = cli_session_setup_nt1_send(
+                       state, ev, cli, user, pass, passlen, ntpass, ntpasslen,
+                       workgroup);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
                }
+               tevent_req_set_callback(subreq, cli_session_setup_done_nt1,
+                                       req);
+               return req;
        }
 
-       return NT_STATUS_OK;
+       tevent_req_done(req);
+       return tevent_req_post(req, ev);
+}
+
+static void cli_session_setup_done_lanman2(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       NTSTATUS status;
+
+       status = cli_session_setup_lanman2_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return;
+       }
+       tevent_req_done(req);
+}
+
+static void cli_session_setup_done_spnego(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       ADS_STATUS status;
+
+       status = cli_session_setup_spnego_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (!ADS_ERR_OK(status)) {
+               DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status)));
+               tevent_req_nterror(req, ads_ntstatus(status));
+               return;
+       }
+       tevent_req_done(req);
+}
+
+static void cli_session_setup_done_guest(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       NTSTATUS status;
+
+       status = cli_session_setup_guest_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return;
+       }
+       tevent_req_done(req);
+}
+
+static void cli_session_setup_done_plain(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       NTSTATUS status;
+
+       status = cli_session_setup_plain_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return;
+       }
+       tevent_req_done(req);
+}
+
+static void cli_session_setup_done_nt1(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       NTSTATUS status;
+
+       status = cli_session_setup_nt1_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(3, ("cli_session_setup: NT1 session setup "
+                         "failed: %s\n", nt_errstr(status)));
+               tevent_req_nterror(req, status);
+               return;
+       }
+       tevent_req_done(req);
+}
+
+NTSTATUS cli_session_setup_recv(struct tevent_req *req)
+{
+       return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_session_setup(struct cli_state *cli,
+                          const char *user,
+                          const char *pass, int passlen,
+                          const char *ntpass, int ntpasslen,
+                          const char *workgroup)
+{
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+       ev = samba_tevent_context_init(talloc_tos());
+       if (ev == NULL) {
+               goto fail;
+       }
+       req = cli_session_setup_send(ev, ev, cli, user, pass, passlen,
+                                    ntpass, ntpasslen, workgroup);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = cli_session_setup_recv(req);
+ fail:
+       TALLOC_FREE(ev);
+       return status;
 }
 
 /****************************************************************************
@@ -2084,7 +2240,7 @@ struct cli_ulogoff_state {
 
 static void cli_ulogoff_done(struct tevent_req *subreq);
 
-struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx,
+static struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx,
                                    struct tevent_context *ev,
                                    struct cli_state *cli)
 {
@@ -2127,7 +2283,7 @@ static void cli_ulogoff_done(struct tevent_req *subreq)
        tevent_req_done(req);
 }
 
-NTSTATUS cli_ulogoff_recv(struct tevent_req *req)
+static NTSTATUS cli_ulogoff_recv(struct tevent_req *req)
 {
        return tevent_req_simple_recv_ntstatus(req);
 }
@@ -2138,10 +2294,10 @@ NTSTATUS cli_ulogoff(struct cli_state *cli)
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                return NT_STATUS_INVALID_PARAMETER;
        }
-       ev = tevent_context_init(talloc_tos());
+       ev = samba_tevent_context_init(talloc_tos());
        if (ev == NULL) {
                goto fail;
        }
@@ -2171,7 +2327,7 @@ struct cli_tcon_andx_state {
 static void cli_tcon_andx_done(struct tevent_req *subreq);
 
 struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx,
-                                       struct event_context *ev,
+                                       struct tevent_context *ev,
                                        struct cli_state *cli,
                                        const char *share, const char *dev,
                                        const char *pass, int passlen,
@@ -2183,7 +2339,8 @@ struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx,
        uint16_t *vwv;
        char *tmp = NULL;
        uint8_t *bytes;
-       uint16_t sec_mode = cli_state_security_mode(cli);
+       uint16_t sec_mode = smb1cli_conn_server_security_mode(cli->conn);
+       uint16_t tcon_flags = 0;
 
        *psmbreq = NULL;
 
@@ -2222,7 +2379,7 @@ struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx,
                 * Non-encrypted passwords - convert to DOS codepage before
                 * encryption.
                 */
-               SMBencrypt(pass, cli->secblob.data, p24);
+               SMBencrypt(pass, smb1cli_conn_server_challenge(cli->conn), p24);
                passlen = 24;
                pass = (const char *)p24;
        } else {
@@ -2232,9 +2389,9 @@ struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx,
                        uint8_t *tmp_pass;
 
                        if (!lp_client_plaintext_auth() && (*pass)) {
-                               DEBUG(1, ("Server requested plaintext "
+                               DEBUG(1, ("Server requested PLAINTEXT "
                                          "password but "
-                                         "'client lanman auth = no' or 'client ntlmv2 auth = yes'\n"));
+                                         "'client plaintext auth = no' or 'client ntlmv2 auth = yes'\n"));
                                goto access_denied;
                        }
 
@@ -2259,10 +2416,13 @@ struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx,
                }
        }
 
+       tcon_flags |= TCONX_FLAG_EXTENDED_RESPONSE;
+       tcon_flags |= TCONX_FLAG_EXTENDED_SIGNATURES;
+
        SCVAL(vwv+0, 0, 0xFF);
        SCVAL(vwv+0, 1, 0);
        SSVAL(vwv+1, 0, 0);
-       SSVAL(vwv+2, 0, TCONX_FLAG_EXTENDED_RESPONSE);
+       SSVAL(vwv+2, 0, tcon_flags);
        SSVAL(vwv+3, 0, passlen);
 
        if (passlen && pass) {
@@ -2275,12 +2435,12 @@ struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx,
         * Add the sharename
         */
        tmp = talloc_asprintf_strupper_m(talloc_tos(), "\\\\%s\\%s",
-                                        cli_state_remote_name(cli), share);
+                                        smbXcli_conn_remote_name(cli->conn), share);
        if (tmp == NULL) {
                TALLOC_FREE(req);
                return NULL;
        }
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1,
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), tmp, strlen(tmp)+1,
                                   NULL);
        TALLOC_FREE(tmp);
 
@@ -2319,7 +2479,7 @@ struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx,
 }
 
 struct tevent_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx,
-                                     struct event_context *ev,
+                                     struct tevent_context *ev,
                                      struct cli_state *cli,
                                      const char *share, const char *dev,
                                      const char *pass, int passlen)
@@ -2335,7 +2495,7 @@ struct tevent_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx,
        if (subreq == NULL) {
                return req;
        }
-       status = cli_smb_req_send(subreq);
+       status = smb1cli_req_chain_submit(&subreq, 1);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
                return tevent_req_post(req, ev);
@@ -2351,12 +2511,13 @@ static void cli_tcon_andx_done(struct tevent_req *subreq)
                req, struct cli_tcon_andx_state);
        struct cli_state *cli = state->cli;
        uint8_t *in;
-       char *inbuf;
+       uint8_t *inhdr;
        uint8_t wct;
        uint16_t *vwv;
        uint32_t num_bytes;
        uint8_t *bytes;
        NTSTATUS status;
+       uint16_t optional_support = 0;
 
        status = cli_smb_recv(subreq, state, &in, 0, &wct, &vwv,
                              &num_bytes, &bytes);
@@ -2366,12 +2527,12 @@ static void cli_tcon_andx_done(struct tevent_req *subreq)
                return;
        }
 
-       inbuf = (char *)in;
+       inhdr = in + NBT_HDR_SIZE;
 
        if (num_bytes) {
                if (clistr_pull_talloc(cli,
-                               inbuf,
-                               SVAL(inbuf, smb_flg2),
+                               (const char *)inhdr,
+                               SVAL(inhdr, HDR_FLG2),
                                &cli->dev,
                                bytes,
                                num_bytes,
@@ -2387,7 +2548,7 @@ static void cli_tcon_andx_done(struct tevent_req *subreq)
                }
        }
 
-       if ((cli_state_protocol(cli) >= PROTOCOL_NT1) && (num_bytes == 3)) {
+       if ((smbXcli_conn_protocol(cli->conn) >= PROTOCOL_NT1) && (num_bytes == 3)) {
                /* almost certainly win95 - enable bug fixes */
                cli->win95 = True;
        }
@@ -2399,11 +2560,19 @@ static void cli_tcon_andx_done(struct tevent_req *subreq)
 
        cli->dfsroot = false;
 
-       if ((wct > 2) && (cli_state_protocol(cli) >= PROTOCOL_LANMAN2)) {
-               cli->dfsroot = ((SVAL(vwv+2, 0) & SMB_SHARE_IN_DFS) != 0);
+       if ((wct > 2) && (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_LANMAN2)) {
+               optional_support = SVAL(vwv+2, 0);
+       }
+
+       if (optional_support & SMB_SHARE_IN_DFS) {
+               cli->dfsroot = true;
+       }
+
+       if (optional_support & SMB_EXTENDED_SIGNATURES) {
+               smb1cli_session_protect_session_key(cli->smb1.session);
        }
 
-       cli->smb1.tid = SVAL(inbuf,smb_tid);
+       cli_state_set_tid(cli, SVAL(inhdr, HDR_TID));
        tevent_req_done(req);
 }
 
@@ -2416,11 +2585,11 @@ NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share,
                       const char *dev, const char *pass, int passlen)
 {
        TALLOC_CTX *frame = talloc_stackframe();
-       struct event_context *ev;
+       struct tevent_context *ev;
        struct tevent_req *req;
-       NTSTATUS status = NT_STATUS_OK;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -2428,20 +2597,17 @@ NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share,
                goto fail;
        }
 
-       ev = event_context_init(frame);
+       ev = samba_tevent_context_init(frame);
        if (ev == NULL) {
-               status = NT_STATUS_NO_MEMORY;
                goto fail;
        }
 
        req = cli_tcon_andx_send(frame, ev, cli, share, dev, pass, passlen);
        if (req == NULL) {
-               status = NT_STATUS_NO_MEMORY;
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -2451,557 +2617,585 @@ NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share,
        return status;
 }
 
-/****************************************************************************
- Send a tree disconnect.
-****************************************************************************/
-
-struct cli_tdis_state {
+struct cli_tree_connect_state {
        struct cli_state *cli;
 };
 
-static void cli_tdis_done(struct tevent_req *subreq);
+static struct tevent_req *cli_raw_tcon_send(
+       TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
+       const char *service, const char *pass, const char *dev);
+static NTSTATUS cli_raw_tcon_recv(struct tevent_req *req,
+                                 uint16 *max_xmit, uint16 *tid);
 
-struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx,
-                                struct tevent_context *ev,
-                                struct cli_state *cli)
+static void cli_tree_connect_smb2_done(struct tevent_req *subreq);
+static void cli_tree_connect_andx_done(struct tevent_req *subreq);
+static void cli_tree_connect_raw_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_tree_connect_send(
+       TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
+       const char *share, const char *dev, const char *pass, int passlen)
 {
        struct tevent_req *req, *subreq;
-       struct cli_tdis_state *state;
+       struct cli_tree_connect_state *state;
 
-       req = tevent_req_create(mem_ctx, &state, struct cli_tdis_state);
+       req = tevent_req_create(mem_ctx, &state,
+                               struct cli_tree_connect_state);
        if (req == NULL) {
                return NULL;
        }
        state->cli = cli;
 
-       subreq = cli_smb_send(state, ev, cli, SMBtdis, 0, 0, NULL, 0, NULL);
+       cli->share = talloc_strdup(cli, share);
+       if (tevent_req_nomem(cli->share, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               subreq = smb2cli_tcon_send(state, ev, cli, share);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
+               }
+               tevent_req_set_callback(subreq, cli_tree_connect_smb2_done,
+                                       req);
+               return req;
+       }
+
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_LANMAN1) {
+               subreq = cli_tcon_andx_send(state, ev, cli, share, dev,
+                                           pass, passlen);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
+               }
+               tevent_req_set_callback(subreq, cli_tree_connect_andx_done,
+                                       req);
+               return req;
+       }
+
+       subreq = cli_raw_tcon_send(state, ev, cli, share, pass, dev);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
-       tevent_req_set_callback(subreq, cli_tdis_done, req);
+       tevent_req_set_callback(subreq, cli_tree_connect_raw_done, req);
+
        return req;
 }
 
-static void cli_tdis_done(struct tevent_req *subreq)
+static void cli_tree_connect_smb2_done(struct tevent_req *subreq)
 {
-       struct tevent_req *req = tevent_req_callback_data(
-               subreq, struct tevent_req);
-       struct cli_tdis_state *state = tevent_req_data(
-               req, struct cli_tdis_state);
-       NTSTATUS status;
+       tevent_req_simple_finish_ntstatus(
+               subreq, smb2cli_tcon_recv(subreq));
+}
 
-       status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
-       TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               tevent_req_nterror(req, status);
+static void cli_tree_connect_andx_done(struct tevent_req *subreq)
+{
+       tevent_req_simple_finish_ntstatus(
+               subreq, cli_tcon_andx_recv(subreq));
+}
+
+static void cli_tree_connect_raw_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_tree_connect_state *state = tevent_req_data(
+               req, struct cli_tree_connect_state);
+       NTSTATUS status;
+       uint16_t max_xmit = 0;
+       uint16_t tid = 0;
+
+       status = cli_raw_tcon_recv(subreq, &max_xmit, &tid);
+       if (tevent_req_nterror(req, status)) {
                return;
        }
-       state->cli->smb1.tid = UINT16_MAX;
+       cli_state_set_tid(state->cli, tid);
        tevent_req_done(req);
 }
 
-NTSTATUS cli_tdis_recv(struct tevent_req *req)
+static NTSTATUS cli_tree_connect_recv(struct tevent_req *req)
 {
        return tevent_req_simple_recv_ntstatus(req);
 }
 
-NTSTATUS cli_tdis(struct cli_state *cli)
+NTSTATUS cli_tree_connect(struct cli_state *cli, const char *share,
+                         const char *dev, const char *pass, int passlen)
 {
        struct tevent_context *ev;
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                return NT_STATUS_INVALID_PARAMETER;
        }
-       ev = tevent_context_init(talloc_tos());
+       ev = samba_tevent_context_init(talloc_tos());
        if (ev == NULL) {
                goto fail;
        }
-       req = cli_tdis_send(ev, ev, cli);
+       req = cli_tree_connect_send(ev, ev, cli, share, dev, pass, passlen);
        if (req == NULL) {
                goto fail;
        }
        if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
-       status = cli_tdis_recv(req);
+       status = cli_tree_connect_recv(req);
 fail:
        TALLOC_FREE(ev);
        return status;
 }
 
 /****************************************************************************
- Send a negprot command.
+ Send a tree disconnect.
 ****************************************************************************/
 
-struct cli_negprot_state {
+struct cli_tdis_state {
        struct cli_state *cli;
-       enum protocol_types max_protocol;
 };
 
-static void cli_negprot_done(struct tevent_req *subreq);
+static void cli_tdis_done(struct tevent_req *subreq);
 
-struct tevent_req *cli_negprot_send(TALLOC_CTX *mem_ctx,
-                                   struct event_context *ev,
-                                   struct cli_state *cli,
-                                   enum protocol_types max_protocol)
+static struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx,
+                                struct tevent_context *ev,
+                                struct cli_state *cli)
 {
        struct tevent_req *req, *subreq;
-       struct cli_negprot_state *state;
-       uint8_t *bytes = NULL;
-       int numprots;
-       enum protocol_types tmp_protocol;
+       struct cli_tdis_state *state;
 
-       req = tevent_req_create(mem_ctx, &state, struct cli_negprot_state);
+       req = tevent_req_create(mem_ctx, &state, struct cli_tdis_state);
        if (req == NULL) {
                return NULL;
        }
        state->cli = cli;
-       state->max_protocol = max_protocol;
 
-       /* setup the protocol strings */
-       for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
-               uint8_t c = 2;
-               if (prots[numprots].prot > state->max_protocol) {
-                       break;
-               }
-               bytes = (uint8_t *)talloc_append_blob(
-                       state, bytes, data_blob_const(&c, sizeof(c)));
-               if (tevent_req_nomem(bytes, req)) {
-                       return tevent_req_post(req, ev);
-               }
-               bytes = smb_bytes_push_str(bytes, false,
-                                          prots[numprots].name,
-                                          strlen(prots[numprots].name)+1,
-                                          NULL);
-               if (tevent_req_nomem(bytes, req)) {
-                       return tevent_req_post(req, ev);
-               }
-       }
-
-       tmp_protocol = cli->conn.protocol;
-       cli->conn.protocol = state->max_protocol;
-       subreq = cli_smb_send(state, ev, cli, SMBnegprot, 0, 0, NULL,
-                             talloc_get_size(bytes), bytes);
-       cli->conn.protocol = tmp_protocol;
+       subreq = cli_smb_send(state, ev, cli, SMBtdis, 0, 0, NULL, 0, NULL);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
-       tevent_req_set_callback(subreq, cli_negprot_done, req);
+       tevent_req_set_callback(subreq, cli_tdis_done, req);
        return req;
 }
 
-static void cli_negprot_done(struct tevent_req *subreq)
+static void cli_tdis_done(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(
                subreq, struct tevent_req);
-       struct cli_negprot_state *state = tevent_req_data(
-               req, struct cli_negprot_state);
-       struct cli_state *cli = state->cli;
-       uint8_t flags;
-       uint8_t wct;
-       uint16_t *vwv;
-       uint32_t num_bytes;
-       uint8_t *bytes;
+       struct cli_tdis_state *state = tevent_req_data(
+               req, struct cli_tdis_state);
        NTSTATUS status;
-       uint16_t protnum;
-       uint8_t *inbuf;
-       uint32_t client_capabilities = cli->conn.smb1.client.capabilities;
-       uint32_t both_capabilities;
-       uint32_t server_capabilities = 0;
-       uint32_t capabilities;
-       uint32_t client_max_xmit = cli->conn.smb1.client.max_xmit;
-       uint32_t server_max_xmit = 0;
-       uint32_t max_xmit;
-       uint32_t server_max_mux = 0;
-       uint16_t server_security_mode = 0;
-       uint32_t server_session_key = 0;
-       bool server_readbraw = false;
-       bool server_writebraw = false;
-       bool server_lockread = false;
-       bool server_writeunlock = false;
-       enum protocol_types protocol;
-
-       status = cli_smb_recv(subreq, state, &inbuf, 1, &wct, &vwv,
-                             &num_bytes, &bytes);
+
+       status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
        TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
                return;
        }
+       cli_state_set_tid(state->cli, UINT16_MAX);
+       tevent_req_done(req);
+}
 
-       flags = CVAL(inbuf, smb_flg);
+static NTSTATUS cli_tdis_recv(struct tevent_req *req)
+{
+       return tevent_req_simple_recv_ntstatus(req);
+}
 
-       protnum = SVAL(vwv, 0);
+NTSTATUS cli_tdis(struct cli_state *cli)
+{
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       if ((protnum >= ARRAY_SIZE(prots))
-           || (prots[protnum].prot > state->max_protocol)) {
-               tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
-               return;
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return smb2cli_tdis(cli);
        }
 
-       protocol = prots[protnum].prot;
-
-       if ((protocol < PROTOCOL_NT1) &&
-           client_is_signing_mandatory(cli)) {
-               DEBUG(0,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n"));
-               tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
-               return;
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
+               return NT_STATUS_INVALID_PARAMETER;
        }
-
-       if (flags & FLAG_SUPPORT_LOCKREAD) {
-               server_lockread = true;
-               server_writeunlock = true;
+       ev = samba_tevent_context_init(talloc_tos());
+       if (ev == NULL) {
+               goto fail;
        }
+       req = cli_tdis_send(ev, ev, cli);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = cli_tdis_recv(req);
+fail:
+       TALLOC_FREE(ev);
+       return status;
+}
 
-       if (protocol >= PROTOCOL_NT1) {
-               struct timespec ts;
-               const char *client_signing = NULL;
-               bool server_mandatory;
-               bool server_allowed;
-               const char *server_signing = NULL;
-               bool ok;
+struct cli_connect_sock_state {
+       const char **called_names;
+       const char **calling_names;
+       int *called_types;
+       int fd;
+       uint16_t port;
+};
 
-               if (wct != 0x11) {
-                       tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
-                       return;
-               }
+static void cli_connect_sock_done(struct tevent_req *subreq);
 
-               /* NT protocol */
-               server_security_mode = CVAL(vwv + 1, 0);
-               server_max_mux = SVAL(vwv + 1, 1);
-               server_max_xmit = IVAL(vwv + 3, 1);
-               server_session_key = IVAL(vwv + 7, 1);
-               cli->serverzone = SVALS(vwv + 15, 1);
-               cli->serverzone *= 60;
-               /* this time arrives in real GMT */
-               ts = interpret_long_date(((char *)(vwv+11))+1);
-               cli->servertime = ts.tv_sec;
-               server_capabilities = IVAL(vwv + 9, 1);
-               if (server_capabilities & CAP_RAW_MODE) {
-                       server_readbraw = true;
-                       server_writebraw = true;
-               }
-               if (server_capabilities & CAP_LOCK_AND_READ) {
-                       server_lockread = true;
-               }
-               if (server_capabilities & CAP_EXTENDED_SECURITY) {
-                       if (num_bytes < 16) {
-                               tevent_req_nterror(req,
-                                       NT_STATUS_INVALID_NETWORK_RESPONSE);
-                               return;
-                       }
-                       cli->secblob = data_blob(bytes+16, num_bytes-16);
-               } else {
-                       cli->secblob = data_blob(bytes, MIN(num_bytes, 8));
-                       /* work out if they sent us a workgroup */
-                       if (num_bytes > 8) {
-                               ssize_t ret;
-                               status = smb_bytes_talloc_string(
-                                       cli, (char *)inbuf, &cli->server_domain,
-                                       bytes + 8, num_bytes - 8, &ret);
-                               if (tevent_req_nterror(req, status)) {
-                                       return;
-                               }
-                       }
-               }
+/*
+ * Async only if we don't have to look up the name, i.e. "pss" is set with a
+ * nonzero address.
+ */
 
-               client_signing = "disabled";
-               if (client_is_signing_allowed(cli)) {
-                       client_signing = "allowed";
-               }
-               if (client_is_signing_mandatory(cli)) {
-                       client_signing = "required";
-               }
+static struct tevent_req *cli_connect_sock_send(
+       TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+       const char *host, int name_type, const struct sockaddr_storage *pss,
+       const char *myname, uint16_t port)
+{
+       struct tevent_req *req, *subreq;
+       struct cli_connect_sock_state *state;
+       const char *prog;
+       unsigned i, num_addrs;
+       NTSTATUS status;
 
-               server_signing = "not supported";
-               if (server_security_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
-                       server_signing = "supported";
-                       server_allowed = true;
-               }
-               if (server_security_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
-                       server_signing = "required";
-                       server_mandatory = true;
-               }
+       req = tevent_req_create(mem_ctx, &state,
+                               struct cli_connect_sock_state);
+       if (req == NULL) {
+               return NULL;
+       }
 
-               ok = cli_set_signing_negotiated(cli,
-                                               server_allowed,
-                                               server_mandatory);
-               if (!ok) {
-                       DEBUG(1,("cli_negprot: SMB signing is required, "
-                                "but client[%s] and server[%s] mismatch\n",
-                                client_signing, server_signing));
-                       tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
-                       return;
+       prog = getenv("LIBSMB_PROG");
+       if (prog != NULL) {
+               state->fd = sock_exec(prog);
+               if (state->fd == -1) {
+                       status = map_nt_error_from_unix(errno);
+                       tevent_req_nterror(req, status);
+               } else {
+                       state->port = 0;
+                       tevent_req_done(req);
                }
+               return tevent_req_post(req, ev);
+       }
 
-       } else if (protocol >= PROTOCOL_LANMAN1) {
-               if (wct != 0x0D) {
-                       tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
-                       return;
-               }
+       if ((pss == NULL) || is_zero_addr(pss)) {
+               struct sockaddr_storage *addrs;
 
-               server_security_mode = SVAL(vwv + 1, 0);
-               server_max_xmit = SVAL(vwv + 2, 0);
-               server_max_mux = SVAL(vwv + 3, 0);
-               server_session_key = IVAL(vwv + 6, 0);
-               cli->serverzone = SVALS(vwv + 10, 0);
-               cli->serverzone *= 60;
-               /* this time is converted to GMT by make_unix_date */
-               cli->servertime = make_unix_date(
-                       (char *)(vwv + 8), cli->serverzone);
-               server_readbraw = ((SVAL(vwv + 5, 0) & 0x1) != 0);
-               server_writebraw = ((SVAL(vwv + 5, 0) & 0x2) != 0);
-               cli->secblob = data_blob(bytes, MIN(num_bytes, 8));
+               /*
+                * Here we cheat. resolve_name_list is not async at all. So
+                * this call will only be really async if the name lookup has
+                * been done externally.
+                */
+
+               status = resolve_name_list(state, host, name_type,
+                                          &addrs, &num_addrs);
+               if (!NT_STATUS_IS_OK(status)) {
+                       tevent_req_nterror(req, status);
+                       return tevent_req_post(req, ev);
+               }
+               pss = addrs;
        } else {
-               /* the old core protocol */
-               cli->serverzone = get_time_zone(time(NULL));
-               server_max_xmit = 1024;
-               server_max_mux = 1;
-               server_security_mode = 0;
+               num_addrs = 1;
        }
 
-       if (server_max_xmit < 1024) {
-               tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
-               return;
+       state->called_names = talloc_array(state, const char *, num_addrs);
+       if (tevent_req_nomem(state->called_names, req)) {
+               return tevent_req_post(req, ev);
+       }
+       state->called_types = talloc_array(state, int, num_addrs);
+       if (tevent_req_nomem(state->called_types, req)) {
+               return tevent_req_post(req, ev);
+       }
+       state->calling_names = talloc_array(state, const char *, num_addrs);
+       if (tevent_req_nomem(state->calling_names, req)) {
+               return tevent_req_post(req, ev);
+       }
+       for (i=0; i<num_addrs; i++) {
+               state->called_names[i] = host;
+               state->called_types[i] = name_type;
+               state->calling_names[i] = myname;
        }
 
-       if (server_max_mux < 1) {
-               tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+       subreq = smbsock_any_connect_send(
+               state, ev, pss, state->called_names, state->called_types,
+               state->calling_names, NULL, num_addrs, port);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, cli_connect_sock_done, req);
+       return req;
+}
+
+static void cli_connect_sock_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_connect_sock_state *state = tevent_req_data(
+               req, struct cli_connect_sock_state);
+       NTSTATUS status;
+
+       status = smbsock_any_connect_recv(subreq, &state->fd, NULL,
+                                         &state->port);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
                return;
        }
+       set_socket_options(state->fd, lp_socket_options());
+       tevent_req_done(req);
+}
 
-       /*
-        * Now calculate the negotiated capabilities
-        * based on the mask for:
-        * - client only flags
-        * - flags used in both directions
-        * - server only flags
-        */
-       both_capabilities = client_capabilities & server_capabilities;
-       capabilities = client_capabilities & SMB_CAP_CLIENT_MASK;
-       capabilities |= both_capabilities & SMB_CAP_BOTH_MASK;
-       capabilities |= server_capabilities & SMB_CAP_SERVER_MASK;
+static NTSTATUS cli_connect_sock_recv(struct tevent_req *req,
+                                     int *pfd, uint16_t *pport)
+{
+       struct cli_connect_sock_state *state = tevent_req_data(
+               req, struct cli_connect_sock_state);
+       NTSTATUS status;
 
-       max_xmit = MIN(client_max_xmit, server_max_xmit);
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
+       }
+       *pfd = state->fd;
+       *pport = state->port;
+       return NT_STATUS_OK;
+}
 
-       cli->conn.protocol = protocol;
+struct cli_connect_nb_state {
+       const char *desthost;
+       int signing_state;
+       int flags;
+       struct cli_state *cli;
+};
 
-       cli->conn.smb1.server.capabilities = server_capabilities;
-       cli->conn.smb1.capabilities = capabilities;
+static void cli_connect_nb_done(struct tevent_req *subreq);
 
-       cli->conn.smb1.server.max_xmit = server_max_xmit;
-       cli->conn.smb1.max_xmit = max_xmit;
+static struct tevent_req *cli_connect_nb_send(
+       TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+       const char *host, const struct sockaddr_storage *dest_ss,
+       uint16_t port, int name_type, const char *myname,
+       int signing_state, int flags)
+{
+       struct tevent_req *req, *subreq;
+       struct cli_connect_nb_state *state;
+       char *p;
 
-       cli->conn.smb1.server.max_mux = server_max_mux;
+       req = tevent_req_create(mem_ctx, &state, struct cli_connect_nb_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->desthost = host;
+       state->signing_state = signing_state;
+       state->flags = flags;
 
-       cli->conn.smb1.server.security_mode = server_security_mode;
+       p = strchr(host, '#');
+       if (p != NULL) {
+               name_type = strtol(p+1, NULL, 16);
+               host = talloc_strndup(state, host, p - host);
+               if (tevent_req_nomem(host, req)) {
+                       return tevent_req_post(req, ev);
+               }
+       }
 
-       cli->conn.smb1.server.readbraw = server_readbraw;
-       cli->conn.smb1.server.writebraw = server_writebraw;
-       cli->conn.smb1.server.lockread = server_lockread;
-       cli->conn.smb1.server.writeunlock = server_writeunlock;
+       subreq = cli_connect_sock_send(state, ev, host, name_type, dest_ss,
+                                      myname, port);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, cli_connect_nb_done, req);
+       return req;
+}
 
-       cli->conn.smb1.server.session_key = server_session_key;
+static void cli_connect_nb_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_connect_nb_state *state = tevent_req_data(
+               req, struct cli_connect_nb_state);
+       NTSTATUS status;
+       int fd;
+       uint16_t port;
+
+       status = cli_connect_sock_recv(subreq, &fd, &port);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
 
+       state->cli = cli_state_create(state, fd, state->desthost, NULL,
+                                     state->signing_state, state->flags);
+       if (tevent_req_nomem(state->cli, req)) {
+               close(fd);
+               return;
+       }
        tevent_req_done(req);
 }
 
-NTSTATUS cli_negprot_recv(struct tevent_req *req)
+static NTSTATUS cli_connect_nb_recv(struct tevent_req *req,
+                                   struct cli_state **pcli)
 {
-       return tevent_req_simple_recv_ntstatus(req);
+       struct cli_connect_nb_state *state = tevent_req_data(
+               req, struct cli_connect_nb_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
+       }
+       *pcli = talloc_move(NULL, &state->cli);
+       return NT_STATUS_OK;
 }
 
-NTSTATUS cli_negprot(struct cli_state *cli, enum protocol_types max_protocol)
+NTSTATUS cli_connect_nb(const char *host, const struct sockaddr_storage *dest_ss,
+                       uint16_t port, int name_type, const char *myname,
+                       int signing_state, int flags, struct cli_state **pcli)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
-       struct event_context *ev;
+       struct tevent_context *ev;
        struct tevent_req *req;
-       NTSTATUS status = NT_STATUS_OK;
-
-       if (cli_has_async_calls(cli)) {
-               /*
-                * Can't use sync call while an async call is in flight
-                */
-               status = NT_STATUS_INVALID_PARAMETER;
-               goto fail;
-       }
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       ev = event_context_init(frame);
+       ev = samba_tevent_context_init(talloc_tos());
        if (ev == NULL) {
-               status = NT_STATUS_NO_MEMORY;
                goto fail;
        }
-
-       req = cli_negprot_send(frame, ev, cli, max_protocol);
+       req = cli_connect_nb_send(ev, ev, host, dest_ss, port, name_type,
+                                 myname, signing_state, flags);
        if (req == NULL) {
-               status = NT_STATUS_NO_MEMORY;
                goto fail;
        }
-
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_set_endtime(req, ev, timeval_current_ofs(20, 0))) {
                goto fail;
        }
-
-       status = cli_negprot_recv(req);
- fail:
-       TALLOC_FREE(frame);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = cli_connect_nb_recv(req, pcli);
+fail:
+       TALLOC_FREE(ev);
        return status;
 }
 
-static NTSTATUS cli_connect_sock(const char *host, int name_type,
-                                const struct sockaddr_storage *pss,
-                                const char *myname, uint16_t port,
-                                int sec_timeout, int *pfd, uint16_t *pport)
-{
-       TALLOC_CTX *frame = talloc_stackframe();
-       const char *prog;
-       unsigned int i, num_addrs;
-       const char **called_names;
-       const char **calling_names;
-       int *called_types;
-       NTSTATUS status;
-       int fd;
+struct cli_start_connection_state {
+       struct tevent_context *ev;
+       struct cli_state *cli;
+};
 
-       prog = getenv("LIBSMB_PROG");
-       if (prog != NULL) {
-               fd = sock_exec(prog);
-               if (fd == -1) {
-                       return map_nt_error_from_unix(errno);
-               }
-               port = 0;
-               goto done;
-       }
+static void cli_start_connection_connected(struct tevent_req *subreq);
+static void cli_start_connection_done(struct tevent_req *subreq);
 
-       if ((pss == NULL) || is_zero_addr(pss)) {
-               struct sockaddr_storage *addrs;
-               status = resolve_name_list(talloc_tos(), host, name_type,
-                                          &addrs, &num_addrs);
-               if (!NT_STATUS_IS_OK(status)) {
-                       goto fail;
-               }
-               pss = addrs;
-       } else {
-               num_addrs = 1;
-       }
+/**
+   establishes a connection to after the negprot. 
+   @param output_cli A fully initialised cli structure, non-null only on success
+   @param dest_host The netbios name of the remote host
+   @param dest_ss (optional) The the destination IP, NULL for name based lookup
+   @param port (optional) The destination port (0 for default)
+*/
 
-       called_names = talloc_array(talloc_tos(), const char *, num_addrs);
-       if (called_names == NULL) {
-               status = NT_STATUS_NO_MEMORY;
-               goto fail;
-       }
-       called_types = talloc_array(talloc_tos(), int, num_addrs);
-       if (called_types == NULL) {
-               status = NT_STATUS_NO_MEMORY;
-               goto fail;
+static struct tevent_req *cli_start_connection_send(
+       TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+       const char *my_name, const char *dest_host,
+       const struct sockaddr_storage *dest_ss, int port,
+       int signing_state, int flags)
+{
+       struct tevent_req *req, *subreq;
+       struct cli_start_connection_state *state;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct cli_start_connection_state);
+       if (req == NULL) {
+               return NULL;
        }
-       calling_names = talloc_array(talloc_tos(), const char *, num_addrs);
-       if (calling_names == NULL) {
-               status = NT_STATUS_NO_MEMORY;
-               goto fail;
+       state->ev = ev;
+
+       subreq = cli_connect_nb_send(state, ev, dest_host, dest_ss, port,
+                                    0x20, my_name, signing_state, flags);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
        }
-       for (i=0; i<num_addrs; i++) {
-               called_names[i] = host;
-               called_types[i] = name_type;
-               calling_names[i] = myname;
+       tevent_req_set_callback(subreq, cli_start_connection_connected, req);
+       return req;
+}
+
+static void cli_start_connection_connected(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_start_connection_state *state = tevent_req_data(
+               req, struct cli_start_connection_state);
+       NTSTATUS status;
+
+       status = cli_connect_nb_recv(subreq, &state->cli);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
        }
-       status = smbsock_any_connect(pss, called_names, called_types,
-                                    calling_names, NULL, num_addrs, port,
-                                    sec_timeout, &fd, NULL, &port);
-       if (!NT_STATUS_IS_OK(status)) {
-               goto fail;
+
+       subreq = smbXcli_negprot_send(state, state->ev, state->cli->conn,
+                                     state->cli->timeout,
+                                     lp_cli_minprotocol(),
+                                     lp_cli_maxprotocol());
+       if (tevent_req_nomem(subreq, req)) {
+               return;
        }
-       set_socket_options(fd, lp_socket_options());
-done:
-       *pfd = fd;
-       *pport = port;
-       status = NT_STATUS_OK;
-fail:
-       TALLOC_FREE(frame);
-       return status;
+       tevent_req_set_callback(subreq, cli_start_connection_done, req);
 }
 
-NTSTATUS cli_connect_nb(const char *host, const struct sockaddr_storage *dest_ss,
-                       uint16_t port, int name_type, const char *myname,
-                       int signing_state, int flags, struct cli_state **pcli)
+static void cli_start_connection_done(struct tevent_req *subreq)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
-       struct cli_state *cli;
-       NTSTATUS status = NT_STATUS_NO_MEMORY;
-       int fd = -1;
-       char *desthost;
-       char *p;
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_start_connection_state *state = tevent_req_data(
+               req, struct cli_start_connection_state);
+       NTSTATUS status;
 
-       desthost = talloc_strdup(talloc_tos(), host);
-       if (desthost == NULL) {
-               goto fail;
+       status = smbXcli_negprot_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
        }
 
-       p = strchr(host, '#');
-       if (p != NULL) {
-               name_type = strtol(p+1, NULL, 16);
-               host = talloc_strndup(talloc_tos(), host, p - host);
-               if (host == NULL) {
-                       goto fail;
-               }
+       if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+               /* Ensure we ask for some initial credits. */
+               smb2cli_conn_set_max_credits(state->cli->conn,
+                                            DEFAULT_SMB2_MAX_CREDITS);
        }
 
-       status = cli_connect_sock(host, name_type, dest_ss, myname, port,
-                                 20, &fd, &port);
-       if (!NT_STATUS_IS_OK(status)) {
-               goto fail;
-       }
+       tevent_req_done(req);
+}
 
-       cli = cli_state_create(NULL, fd, desthost, NULL, signing_state, flags);
-       if (cli == NULL) {
-               goto fail;
+static NTSTATUS cli_start_connection_recv(struct tevent_req *req,
+                                         struct cli_state **output_cli)
+{
+       struct cli_start_connection_state *state = tevent_req_data(
+               req, struct cli_start_connection_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
        }
+       *output_cli = state->cli;
 
-       *pcli = cli;
-       status = NT_STATUS_OK;
-fail:
-       TALLOC_FREE(frame);
-       return status;
+       return NT_STATUS_OK;
 }
 
-/**
-   establishes a connection to after the negprot. 
-   @param output_cli A fully initialised cli structure, non-null only on success
-   @param dest_host The netbios name of the remote host
-   @param dest_ss (optional) The the destination IP, NULL for name based lookup
-   @param port (optional) The destination port (0 for default)
-*/
 NTSTATUS cli_start_connection(struct cli_state **output_cli, 
                              const char *my_name, 
                              const char *dest_host, 
                              const struct sockaddr_storage *dest_ss, int port,
                              int signing_state, int flags)
 {
-       NTSTATUS nt_status;
-       struct cli_state *cli;
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       nt_status = cli_connect_nb(dest_host, dest_ss, port, 0x20, my_name,
-                                  signing_state, flags, &cli);
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               DEBUG(10, ("cli_connect_nb failed: %s\n",
-                          nt_errstr(nt_status)));
-               return nt_status;
+       ev = samba_tevent_context_init(talloc_tos());
+       if (ev == NULL) {
+               goto fail;
        }
-
-       nt_status = cli_negprot(cli, PROTOCOL_NT1);
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               DEBUG(1, ("failed negprot: %s\n", nt_errstr(nt_status)));
-               cli_shutdown(cli);
-               return nt_status;
+       req = cli_start_connection_send(ev, ev, my_name, dest_host, dest_ss,
+                                       port, signing_state, flags);
+       if (req == NULL) {
+               goto fail;
        }
-
-       *output_cli = cli;
-       return NT_STATUS_OK;
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = cli_start_connection_recv(req, output_cli);
+fail:
+       TALLOC_FREE(ev);
+       return status;
 }
 
-
 /**
    establishes a connection right up to doing tconX, password specified.
    @param output_cli A fully initialised cli structure, non-null only on success
@@ -3015,118 +3209,327 @@ NTSTATUS cli_start_connection(struct cli_state **output_cli,
    @param password User's password, unencrypted unix string.
 */
 
-NTSTATUS cli_full_connection(struct cli_state **output_cli, 
-                            const char *my_name, 
-                            const char *dest_host, 
-                            const struct sockaddr_storage *dest_ss, int port,
-                            const char *service, const char *service_type,
-                            const char *user, const char *domain, 
-                            const char *password, int flags,
-                            int signing_state)
+struct cli_full_connection_state {
+       struct tevent_context *ev;
+       const char *service;
+       const char *service_type;
+       const char *user;
+       const char *domain;
+       const char *password;
+       int pw_len;
+       int flags;
+       struct cli_state *cli;
+};
+
+static int cli_full_connection_state_destructor(
+       struct cli_full_connection_state *s);
+static void cli_full_connection_started(struct tevent_req *subreq);
+static void cli_full_connection_sess_set_up(struct tevent_req *subreq);
+static void cli_full_connection_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_full_connection_send(
+       TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+       const char *my_name, const char *dest_host,
+       const struct sockaddr_storage *dest_ss, int port,
+       const char *service, const char *service_type,
+       const char *user, const char *domain,
+       const char *password, int flags, int signing_state)
 {
-       NTSTATUS nt_status;
-       struct cli_state *cli = NULL;
-       int pw_len = password ? strlen(password)+1 : 0;
+       struct tevent_req *req, *subreq;
+       struct cli_full_connection_state *state;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct cli_full_connection_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       talloc_set_destructor(state, cli_full_connection_state_destructor);
+
+       state->ev = ev;
+       state->service = service;
+       state->service_type = service_type;
+       state->user = user;
+       state->domain = domain;
+       state->password = password;
+       state->flags = flags;
+
+       state->pw_len = state->password ? strlen(state->password)+1 : 0;
+       if (state->password == NULL) {
+               state->password = "";
+       }
 
-       *output_cli = NULL;
+       subreq = cli_start_connection_send(
+               state, ev, my_name, dest_host, dest_ss, port,
+               signing_state, flags);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, cli_full_connection_started, req);
+       return req;
+}
 
-       if (password == NULL) {
-               password = "";
+static int cli_full_connection_state_destructor(
+       struct cli_full_connection_state *s)
+{
+       if (s->cli != NULL) {
+               cli_shutdown(s->cli);
+               s->cli = NULL;
        }
+       return 0;
+}
 
-       nt_status = cli_start_connection(&cli, my_name, dest_host,
-                                        dest_ss, port, signing_state,
-                                        flags);
+static void cli_full_connection_started(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_full_connection_state *state = tevent_req_data(
+               req, struct cli_full_connection_state);
+       NTSTATUS status;
 
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               return nt_status;
+       status = cli_start_connection_recv(subreq, &state->cli);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       subreq = cli_session_setup_send(
+               state, state->ev, state->cli, state->user,
+               state->password, state->pw_len, state->password, state->pw_len,
+               state->domain);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
        }
+       tevent_req_set_callback(subreq, cli_full_connection_sess_set_up, req);
+}
 
-       nt_status = cli_session_setup(cli, user, password, pw_len, password,
-                                     pw_len, domain);
-       if (!NT_STATUS_IS_OK(nt_status)) {
+static void cli_full_connection_sess_set_up(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_full_connection_state *state = tevent_req_data(
+               req, struct cli_full_connection_state);
+       NTSTATUS status;
 
-               if (!(flags & CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK)) {
-                       DEBUG(1,("failed session setup with %s\n",
-                                nt_errstr(nt_status)));
-                       cli_shutdown(cli);
-                       return nt_status;
-               }
+       status = cli_session_setup_recv(subreq);
+       TALLOC_FREE(subreq);
+
+       if (!NT_STATUS_IS_OK(status) &&
+           (state->flags & CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK)) {
 
-               nt_status = cli_session_setup(cli, "", "", 0, "", 0, domain);
-               if (!NT_STATUS_IS_OK(nt_status)) {
-                       DEBUG(1,("anonymous failed session setup with %s\n",
-                                nt_errstr(nt_status)));
-                       cli_shutdown(cli);
-                       return nt_status;
+               state->flags &= ~CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK;
+
+               subreq = cli_session_setup_send(
+                       state, state->ev, state->cli, "", "", 0, "", 0,
+                       state->domain);
+               if (tevent_req_nomem(subreq, req)) {
+                       return;
                }
+               tevent_req_set_callback(
+                       subreq, cli_full_connection_sess_set_up, req);
+               return;
        }
 
-       if (service) {
-               nt_status = cli_tcon_andx(cli, service, service_type, password,
-                                         pw_len);
-               if (!NT_STATUS_IS_OK(nt_status)) {
-                       DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
-                       cli_shutdown(cli);
-                       if (NT_STATUS_IS_OK(nt_status)) {
-                               nt_status = NT_STATUS_UNSUCCESSFUL;
-                       }
-                       return nt_status;
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+
+       if (state->service != NULL) {
+               subreq = cli_tree_connect_send(
+                       state, state->ev, state->cli,
+                       state->service, state->service_type,
+                       state->password, state->pw_len);
+               if (tevent_req_nomem(subreq, req)) {
+                       return;
                }
+               tevent_req_set_callback(subreq, cli_full_connection_done, req);
+               return;
+       }
+
+       status = cli_init_creds(state->cli, state->user, state->domain,
+                               state->password);
+       if (tevent_req_nterror(req, status)) {
+               return;
        }
+       tevent_req_done(req);
+}
+
+static void cli_full_connection_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_full_connection_state *state = tevent_req_data(
+               req, struct cli_full_connection_state);
+       NTSTATUS status;
 
-       nt_status = cli_init_creds(cli, user, domain, password);
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               cli_shutdown(cli);
-               return nt_status;
+       status = cli_tree_connect_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       status = cli_init_creds(state->cli, state->user, state->domain,
+                               state->password);
+       if (tevent_req_nterror(req, status)) {
+               return;
        }
+       tevent_req_done(req);
+}
+
+NTSTATUS cli_full_connection_recv(struct tevent_req *req,
+                                 struct cli_state **output_cli)
+{
+       struct cli_full_connection_state *state = tevent_req_data(
+               req, struct cli_full_connection_state);
+       NTSTATUS status;
 
-       *output_cli = cli;
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
+       }
+       *output_cli = state->cli;
+       talloc_set_destructor(state, NULL);
        return NT_STATUS_OK;
 }
 
+NTSTATUS cli_full_connection(struct cli_state **output_cli,
+                            const char *my_name,
+                            const char *dest_host,
+                            const struct sockaddr_storage *dest_ss, int port,
+                            const char *service, const char *service_type,
+                            const char *user, const char *domain,
+                            const char *password, int flags,
+                            int signing_state)
+{
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       ev = samba_tevent_context_init(talloc_tos());
+       if (ev == NULL) {
+               goto fail;
+       }
+       req = cli_full_connection_send(
+               ev, ev, my_name, dest_host, dest_ss, port, service,
+               service_type, user, domain, password, flags, signing_state);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = cli_full_connection_recv(req, output_cli);
+ fail:
+       TALLOC_FREE(ev);
+       return status;
+}
+
 /****************************************************************************
  Send an old style tcon.
 ****************************************************************************/
-NTSTATUS cli_raw_tcon(struct cli_state *cli, 
-                     const char *service, const char *pass, const char *dev,
-                     uint16 *max_xmit, uint16 *tid)
-{
-       struct tevent_req *req;
+struct cli_raw_tcon_state {
        uint16_t *ret_vwv;
+};
+
+static void cli_raw_tcon_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_raw_tcon_send(
+       TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
+       const char *service, const char *pass, const char *dev)
+{
+       struct tevent_req *req, *subreq;
+       struct cli_raw_tcon_state *state;
        uint8_t *bytes;
-       NTSTATUS status;
+
+       req = tevent_req_create(mem_ctx, &state, struct cli_raw_tcon_state);
+       if (req == NULL) {
+               return NULL;
+       }
 
        if (!lp_client_plaintext_auth() && (*pass)) {
-               DEBUG(1, ("Server requested plaintext password but 'client "
-                         "plaintext auth' is disabled\n"));
-               return NT_STATUS_ACCESS_DENIED;
+               DEBUG(1, ("Server requested PLAINTEXT password but 'client plaintext auth = no'"
+                         " or 'client ntlmv2 auth = yes'\n"));
+               tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+               return tevent_req_post(req, ev);
        }
 
-       bytes = talloc_array(talloc_tos(), uint8_t, 0);
+       bytes = talloc_array(state, uint8_t, 0);
        bytes = smb_bytes_push_bytes(bytes, 4, NULL, 0);
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
                                   service, strlen(service)+1, NULL);
        bytes = smb_bytes_push_bytes(bytes, 4, NULL, 0);
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
                                   pass, strlen(pass)+1, NULL);
        bytes = smb_bytes_push_bytes(bytes, 4, NULL, 0);
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
                                   dev, strlen(dev)+1, NULL);
 
-       status = cli_smb(talloc_tos(), cli, SMBtcon, 0, 0, NULL,
-                        talloc_get_size(bytes), bytes, &req,
-                        2, NULL, &ret_vwv, NULL, NULL);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       if (tevent_req_nomem(bytes, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       subreq = cli_smb_send(state, ev, cli, SMBtcon, 0, 0, NULL,
+                             talloc_get_size(bytes), bytes);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, cli_raw_tcon_done, req);
+       return req;
+}
+
+static void cli_raw_tcon_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_raw_tcon_state *state = tevent_req_data(
+               req, struct cli_raw_tcon_state);
+       NTSTATUS status;
+
+       status = cli_smb_recv(subreq, state, NULL, 2, NULL, &state->ret_vwv,
+                             NULL, NULL);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
        }
+       tevent_req_done(req);
+}
 
-       *max_xmit = SVAL(ret_vwv + 0, 0);
-       *tid = SVAL(ret_vwv + 1, 0);
+static NTSTATUS cli_raw_tcon_recv(struct tevent_req *req,
+                                 uint16 *max_xmit, uint16 *tid)
+{
+       struct cli_raw_tcon_state *state = tevent_req_data(
+               req, struct cli_raw_tcon_state);
+       NTSTATUS status;
 
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
+       }
+       *max_xmit = SVAL(state->ret_vwv + 0, 0);
+       *tid = SVAL(state->ret_vwv + 1, 0);
        return NT_STATUS_OK;
 }
 
+NTSTATUS cli_raw_tcon(struct cli_state *cli,
+                     const char *service, const char *pass, const char *dev,
+                     uint16 *max_xmit, uint16 *tid)
+{
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       ev = samba_tevent_context_init(talloc_tos());
+       if (ev == NULL) {
+               goto fail;
+       }
+       req = cli_raw_tcon_send(ev, ev, cli, service, pass, dev);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = cli_raw_tcon_recv(req, max_xmit, tid);
+fail:
+       TALLOC_FREE(ev);
+       return status;
+}
+
 /* Return a cli_state pointing at the IPC$ share for the given server */
 
 struct cli_state *get_ipc_connect(char *server,
@@ -3146,7 +3549,7 @@ struct cli_state *get_ipc_connect(char *server,
                                        lp_workgroup(),
                                        user_info->password ? user_info->password : "",
                                        flags,
-                                       Undefined);
+                                       SMB_SIGNING_DEFAULT);
 
        if (NT_STATUS_IS_OK(nt_status)) {
                return cli;
@@ -3250,7 +3653,7 @@ struct cli_state *get_ipc_connect_master_ip_bcast(TALLOC_CTX *ctx,
         if (!NT_STATUS_IS_OK(status)) {
                 DEBUG(99, ("No master browsers responded: %s\n",
                           nt_errstr(status)));
-                return False;
+                return NULL;
         }
 
        for (i = 0; i < count; i++) {