summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2013-04-05 14:55:26 +0200
committerJeremy Allison <jra@samba.org>2013-04-11 14:52:56 -0700
commitcd2cc97df214a284c55fc5bf43d17aab10808d95 (patch)
tree66b67f1a823175dcdf8c0a8b9786293cdcd9a41a
parent5daf6476fa431bea2815f1e7afbfea3688d39d19 (diff)
downloadsamba-cd2cc97df214a284c55fc5bf43d17aab10808d95.tar.gz
samba-cd2cc97df214a284c55fc5bf43d17aab10808d95.tar.bz2
samba-cd2cc97df214a284c55fc5bf43d17aab10808d95.zip
libsmbclient: Make cli_full_connection async
Signed-off-by: Volker Lendecke <vl@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org>
-rw-r--r--source3/libsmb/cliconnect.c240
-rw-r--r--source3/libsmb/proto.h9
2 files changed, 199 insertions, 50 deletions
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index b5055cc34f..3242d8c965 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -3186,7 +3186,6 @@ fail:
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
@@ -3200,76 +3199,217 @@ fail:
@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);
- *output_cli = NULL;
+ 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 = "";
+ }
+
+ 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);
+}
+
+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;
+
+ status = cli_session_setup_recv(subreq);
+ TALLOC_FREE(subreq);
- nt_status = cli_session_setup(cli, user, password, pw_len, password,
- pw_len, domain);
- if (!NT_STATUS_IS_OK(nt_status)) {
+ if (!NT_STATUS_IS_OK(status) &&
+ (state->flags & CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK)) {
- 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;
- }
+ 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;
+ 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_tree_connect(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;
}
- nt_status = cli_init_creds(cli, user, domain, password);
- if (!NT_STATUS_IS_OK(nt_status)) {
- cli_shutdown(cli);
- return nt_status;
+ 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;
+
+ 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.
****************************************************************************/
diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
index 182750c60f..48496c8847 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -88,6 +88,15 @@ NTSTATUS cli_start_connection(struct cli_state **output_cli,
const char *dest_host,
const struct sockaddr_storage *dest_ss, int port,
int signing_state, int flags);
+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 cli_full_connection_recv(struct tevent_req *req,
+ struct cli_state **output_cli);
NTSTATUS cli_full_connection(struct cli_state **output_cli,
const char *my_name,
const char *dest_host,