From cd2cc97df214a284c55fc5bf43d17aab10808d95 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 5 Apr 2013 14:55:26 +0200 Subject: [PATCH] libsmbclient: Make cli_full_connection async Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/libsmb/cliconnect.c | 240 +++++++++++++++++++++++++++++++++++--------- source3/libsmb/proto.h | 9 ++ 2 files changed, 199 insertions(+), 50 deletions(-) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index b5055cc34f7..3242d8c965d 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 182750c60fc..48496c8847c 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, -- 2.11.4.GIT