Patchset: async cli_session_setup

Volker Lendecke Volker.Lendecke at SerNet.DE
Thu Apr 4 03:35:06 MDT 2013


Hi!

Attached find a patchset that makes cli_session_setup in
source3/libsmb more async. It does not handle the kinit
process, but all non-kerberos variants should be properly
async now.

Please review & potentially push.

Thanks,

Volker

-- 
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de, mailto:kontakt at sernet.de
-------------- next part --------------
From 23210496618e8ee08154249dec7bda337beed24d Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 8 Mar 2013 17:40:54 +0100
Subject: [PATCH 1/8] libsmbclient: Fix a leak on talloc_tos()

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/libsmb/cliconnect.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index ec5c273..d0e67db 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -2015,7 +2015,9 @@ ntlmssp:
 		account[PTR_DIFF(p,user)] = '\0';
 	}
 
-	return ADS_ERROR_NT(cli_session_setup_ntlmssp(cli, account, pass, user_domain));
+	status = cli_session_setup_ntlmssp(cli, account, pass, user_domain);
+	TALLOC_FREE(account);
+	return ADS_ERROR_NT(status);
 }
 
 /****************************************************************************
-- 
1.7.0.4


From f2eefe52a429c16c36c071eed033922a2381e248 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 8 Mar 2013 15:55:51 +0100
Subject: [PATCH 2/8] libsmbclient: Avoid a data copy

spnego_parse_negTokenInit does a asn_load of that blob, which does a data copy
itself. So we don't have to had it a copy as well.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/libsmb/cliconnect.c |   14 +++++---------
 1 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index d0e67db..a67d25f 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -1875,20 +1875,17 @@ static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli,
 	char *OIDs[ASN1_MAX_OIDS];
 	int i;
 	const DATA_BLOB *server_blob;
-	DATA_BLOB blob = data_blob_null;
 	const char *p = NULL;
 	char *account = NULL;
 	NTSTATUS status;
 
 	server_blob = smbXcli_conn_server_gss_blob(cli->conn);
-	if (server_blob) {
-		blob = data_blob(server_blob->data, server_blob->length);
-	}
 
-	DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)blob.length));
+	DEBUG(3,("Doing spnego session setup (blob length=%lu)\n",
+		 (unsigned long)server_blob->length));
 
 	/* the server might not even do spnego */
-	if (blob.length == 0) {
+	if (server_blob->length == 0) {
 		DEBUG(3,("server didn't supply a full spnego negprot\n"));
 		goto ntlmssp;
 	}
@@ -1901,12 +1898,11 @@ static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli,
 	 * 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(talloc_tos(), *server_blob, OIDs,
+				       &principal, NULL) ||
 			OIDs[0] == NULL) {
-		data_blob_free(&blob);
 		return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
 	}
-	data_blob_free(&blob);
 
 	/* make sure the server understands kerberos */
 	for (i=0;OIDs[i];i++) {
-- 
1.7.0.4


From b71a0177cba67034da86a1c497c2c2a649f31706 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 8 Mar 2013 17:21:13 +0100
Subject: [PATCH 3/8] libsmbclient: Factor out cli_session_setup_get_principal

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/libsmb/cliconnect.c |   85 +++++++++++++++++++++++++------------------
 1 files changed, 49 insertions(+), 36 deletions(-)

diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index a67d25f..742921d 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -1858,6 +1858,50 @@ fail:
 	return status;
 }
 
+#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)
+{
+	char *principal = NULL;
+
+	if (!lp_client_use_spnego_principal() ||
+	    strequal(principal, ADS_IGNORE_PRINCIPAL)) {
+		spnego_principal = NULL;
+	}
+	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);
+	}
+	if (is_ipaddress(remote_name) ||
+	    strequal(remote_name, STAR_SMBSERVER)) {
+		return NULL;
+	}
+
+	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());
+	}
+	DEBUG(3, ("cli_session_setup_spnego: guessed server principal=%s\n",
+		  principal ? principal : "<null>"));
+
+	return principal;
+}
+#endif
+
 /****************************************************************************
  Do a spnego encrypted session setup.
 
@@ -1932,6 +1976,7 @@ static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli,
 	if (user && *user && cli->got_kerberos_mechanism && cli->use_kerberos) {
 		ADS_STATUS rc;
 		const char *remote_name = smbXcli_conn_remote_name(cli->conn);
+		char *tmp;
 
 		if (pass && *pass) {
 			int ret;
@@ -1948,42 +1993,10 @@ static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli,
 			}
 		}
 
-		/* 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)) {
-			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) {
-					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());
-			}
-
-			if (!principal) {
-				return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
-			}
-			DEBUG(3,("cli_session_setup_spnego: guessed "
-				"server principal=%s\n",
-				principal ? principal : "<null>"));
-		}
+		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);
-- 
1.7.0.4


From 653dcca03abce989b09a3f0c0d8a27eb77f6a106 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 8 Mar 2013 19:41:07 +0100
Subject: [PATCH 4/8] libsmbclient: Slightly simplify cli_session_setup_spnego

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/libsmb/cliconnect.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index 742921d..253cc70 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -1919,7 +1919,7 @@ static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli,
 	char *OIDs[ASN1_MAX_OIDS];
 	int i;
 	const DATA_BLOB *server_blob;
-	const char *p = NULL;
+	char *p;
 	char *account = NULL;
 	NTSTATUS status;
 
@@ -2020,8 +2020,8 @@ ntlmssp:
 	/* when falling back to ntlmssp while authenticating with a machine
 	 * account strip off the realm - gd */
 
-	if ((p = strchr_m(user, '@')) != NULL) {
-		account[PTR_DIFF(p,user)] = '\0';
+	if ((p = strchr_m(account, '@')) != NULL) {
+		*p = '\0';
 	}
 
 	status = cli_session_setup_ntlmssp(cli, account, pass, user_domain);
-- 
1.7.0.4


From 454ad4de265efff1a61c5e1eee95f5bcb30e5d03 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sat, 9 Mar 2013 09:53:42 +0100
Subject: [PATCH 5/8] libsmbclient: Factor out cli_session_setup_get_account

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/libsmb/cliconnect.c |   26 +++++++++++++++++---------
 1 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index 253cc70..212cc3e 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -1902,6 +1902,22 @@ static char *cli_session_setup_get_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;
+}
+
 /****************************************************************************
  Do a spnego encrypted session setup.
 
@@ -1919,7 +1935,6 @@ static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli,
 	char *OIDs[ASN1_MAX_OIDS];
 	int i;
 	const DATA_BLOB *server_blob;
-	char *p;
 	char *account = NULL;
 	NTSTATUS status;
 
@@ -2012,18 +2027,11 @@ static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli,
 
 ntlmssp:
 
-	account = talloc_strdup(talloc_tos(), user);
+	account = cli_session_setup_get_account(talloc_tos(), user);
 	if (!account) {
 		return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
 	}
 
-	/* when falling back to ntlmssp while authenticating with a machine
-	 * account strip off the realm - gd */
-
-	if ((p = strchr_m(account, '@')) != NULL) {
-		*p = '\0';
-	}
-
 	status = cli_session_setup_ntlmssp(cli, account, pass, user_domain);
 	TALLOC_FREE(account);
 	return ADS_ERROR_NT(status);
-- 
1.7.0.4


From a4f23eb70e83e8b1a81cef344287f290385fc8d3 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sat, 9 Mar 2013 13:07:57 +0100
Subject: [PATCH 6/8] libsmbclient: Add async cli_session_setup_ntlmssp

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/libsmb/cliconnect.c |  169 +++++++++++++++++++++++++++++++++++++------
 1 files changed, 146 insertions(+), 23 deletions(-)

diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index 212cc3e..09694be 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -1925,19 +1925,53 @@ static char *cli_session_setup_get_account(TALLOC_CTX *mem_ctx,
  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;
 	const DATA_BLOB *server_blob;
-	char *account = NULL;
 	NTSTATUS status;
 
+	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",
@@ -1957,10 +1991,12 @@ static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli,
 	 * 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(), *server_blob, OIDs,
+	if (!spnego_parse_negTokenInit(state, *server_blob, OIDs,
 				       &principal, NULL) ||
 			OIDs[0] == NULL) {
-		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);
 	}
 
 	/* make sure the server understands kerberos */
@@ -1980,8 +2016,9 @@ 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
@@ -2004,7 +2041,9 @@ 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);
 			}
 		}
 
@@ -2014,27 +2053,111 @@ static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli,
 		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:
+	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);
 
-	account = cli_session_setup_get_account(talloc_tos(), user);
-	if (!account) {
-		return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+	state->result = cli_session_setup_kerberos_recv(subreq);
+	TALLOC_FREE(subreq);
+
+	if (ADS_ERR_OK(state->result) ||
+	    !state->cli->fallback_after_kerberos) {
+		tevent_req_done(req);
+		return;
+	}
+
+	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 state->result;
+}
+
+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 tevent_context *ev;
+	struct tevent_req *req;
+	ADS_STATUS result = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+	NTSTATUS status;
 
-	status = cli_session_setup_ntlmssp(cli, account, pass, user_domain);
-	TALLOC_FREE(account);
-	return ADS_ERROR_NT(status);
+	if (smbXcli_conn_has_async_calls(cli->conn)) {
+		return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+	}
+	ev = samba_tevent_context_init(talloc_tos());
+	if (ev == NULL) {
+		goto fail;
+	}
+	req = cli_session_setup_spnego_send(ev, ev, cli, user, pass,
+					    user_domain, dest_realm);
+	if (req == NULL) {
+		goto fail;
+	}
+	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+		result = ADS_ERROR_NT(status);
+		goto fail;
+	}
+	result = cli_session_setup_spnego_recv(req);
+fail:
+	TALLOC_FREE(ev);
+	return result;
 }
 
 /****************************************************************************
-- 
1.7.0.4


From eb9ddb043d0e2b7f7687dee2ac0bd13c31f39cde Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 2 Apr 2013 12:50:43 +0200
Subject: [PATCH 7/8] libsmbclient: Remove unused cli_session_setup_ntlmssp()

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/libsmb/cliconnect.c |   29 -----------------------------
 1 files changed, 0 insertions(+), 29 deletions(-)

diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index 09694be..df5d895 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -1829,35 +1829,6 @@ 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)
-{
-	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_ntlmssp_send(ev, ev, cli, user, pass, domain);
-	if (req == NULL) {
-		goto fail;
-	}
-	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
-		goto fail;
-	}
-	status = cli_session_setup_ntlmssp_recv(req);
-fail:
-	TALLOC_FREE(ev);
-	return status;
-}
-
 #ifdef HAVE_KRB5
 
 static char *cli_session_setup_get_principal(
-- 
1.7.0.4


From 727bdf5c734e06f5e4f18fd122997df3758ef50f Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 2 Apr 2013 13:37:30 +0200
Subject: [PATCH 8/8] libsmbclient: Add async cli_session_setup

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/libsmb/cliconnect.c |  262 ++++++++++++++++++++++++++++++++++++-------
 source3/libsmb/proto.h      |    8 ++
 2 files changed, 228 insertions(+), 42 deletions(-)

diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index df5d895..8383fa3 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -2131,29 +2131,50 @@ fail:
 	return 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 = 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) {
@@ -2166,13 +2187,15 @@ NTSTATUS cli_session_setup(struct cli_state *cli,
 		*p = 0;
 		user = p+1;
 		if (!strupper_m(user2)) {
-			return NT_STATUS_INVALID_PARAMETER;
+			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+			return tevent_req_post(req, ev);
 		}
 		workgroup = user2;
 	}
 
 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_LANMAN1) {
-		return NT_STATUS_OK;
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
 	}
 
 	/* now work out what sort of session setup we are going to
@@ -2185,44 +2208,68 @@ NTSTATUS cli_session_setup(struct cli_state *cli,
 		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 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);
 		}
 
-		return cli_session_setup_lanman2(cli, user, pass, passlen,
-						 workgroup);
+		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);
-		ADS_STATUS status = cli_session_setup_spnego(cli, user, pass,
-							     workgroup,
-							     remote_realm);
-		if (!ADS_ERR_OK(status)) {
-			DEBUG(3, ("SMB2-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);
 		}
-		return NT_STATUS_OK;
+		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 */
@@ -2231,36 +2278,167 @@ NTSTATUS cli_session_setup(struct cli_state *cli,
 		if (!lp_client_plaintext_auth() && (*pass)) {
 			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 (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)
+{
+	TALLOC_CTX *frame = talloc_stackframe();
+	struct tevent_context *ev;
+	struct tevent_req *req;
+	NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+	if (smbXcli_conn_has_async_calls(cli->conn)) {
+		/*
+		 * Can't use sync call while an async call is in flight
+		 */
+		status = NT_STATUS_INVALID_PARAMETER;
+		goto fail;
+	}
+	ev = samba_tevent_context_init(frame);
+	if (ev == NULL) {
+		goto fail;
+	}
+	req = cli_session_setup_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_recv(req);
+ fail:
+	TALLOC_FREE(frame);
+	return status;
 }
 
 /****************************************************************************
diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
index 2d0e782..182750c 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -33,6 +33,14 @@ struct smb_trans_enc_state;
 
 /* The following definitions come from libsmb/cliconnect.c  */
 
+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);
+NTSTATUS cli_session_setup_recv(struct tevent_req *req);
 NTSTATUS cli_session_setup(struct cli_state *cli,
 			   const char *user,
 			   const char *pass, int passlen,
-- 
1.7.0.4



More information about the samba-technical mailing list