diff options
Diffstat (limited to 'source4/libcli/smb2/connect.c')
-rw-r--r-- | source4/libcli/smb2/connect.c | 448 |
1 files changed, 265 insertions, 183 deletions
diff --git a/source4/libcli/smb2/connect.c b/source4/libcli/smb2/connect.c index 64ed6c3acc..0e3bf1512b 100644 --- a/source4/libcli/smb2/connect.c +++ b/source4/libcli/smb2/connect.c @@ -20,6 +20,8 @@ */ #include "includes.h" +#include <tevent.h> +#include "lib/util/tevent_ntstatus.h" #include "libcli/raw/libcliraw.h" #include "libcli/raw/raw_proto.h" #include "libcli/smb2/smb2.h" @@ -29,6 +31,7 @@ #include "param/param.h" struct smb2_connect_state { + struct tevent_context *ev; struct cli_credentials *credentials; struct resolve_context *resolve_ctx; const char *host; @@ -43,67 +46,167 @@ struct smb2_connect_state { struct smb2_tree *tree; }; +static void smb2_connect_resolve_done(struct composite_context *creq); + /* - continue after tcon reply -*/ -static void continue_tcon(struct smb2_request *req) + a composite function that does a full negprot/sesssetup/tcon, returning + a connected smb2_tree + */ +struct tevent_req *smb2_connect_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const char *host, + const char **ports, + const char *share, + struct resolve_context *resolve_ctx, + struct cli_credentials *credentials, + struct smbcli_options *options, + const char *socket_options, + struct gensec_settings *gensec_settings) { - struct composite_context *c = talloc_get_type(req->async.private_data, - struct composite_context); - struct smb2_connect_state *state = talloc_get_type(c->private_data, - struct smb2_connect_state); - - c->status = smb2_tree_connect_recv(req, &state->tcon); - if (!composite_is_ok(c)) return; - - state->tree->tid = state->tcon.out.tid; + struct tevent_req *req; + struct smb2_connect_state *state; + struct nbt_name name; + struct composite_context *creq; + + req = tevent_req_create(mem_ctx, &state, + struct smb2_connect_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->credentials = credentials; + state->options = *options; + state->host = host; + state->ports = ports; + state->share = share; + state->resolve_ctx = resolve_ctx; + state->socket_options = socket_options; + state->gensec_settings = gensec_settings; + + ZERO_STRUCT(name); + name.name = host; - composite_done(c); + creq = resolve_name_send(resolve_ctx, state, &name, ev); + if (tevent_req_nomem(creq, req)) { + return tevent_req_post(req, ev); + } + creq->async.fn = smb2_connect_resolve_done; + creq->async.private_data = req; + return req; } -/* - continue after a session setup -*/ -static void continue_session(struct composite_context *creq) +static void smb2_connect_socket_done(struct composite_context *creq); + +static void smb2_connect_resolve_done(struct composite_context *creq) { - struct composite_context *c = talloc_get_type(creq->async.private_data, - struct composite_context); - struct smb2_connect_state *state = talloc_get_type(c->private_data, - struct smb2_connect_state); - struct smb2_request *req; + struct tevent_req *req = + talloc_get_type_abort(creq->async.private_data, + struct tevent_req); + struct smb2_connect_state *state = + tevent_req_data(req, + struct smb2_connect_state); + NTSTATUS status; + const char *addr; + const char **ports; + const char *default_ports[] = { "445", NULL }; - c->status = smb2_session_setup_spnego_recv(creq); - if (!composite_is_ok(c)) return; + status = resolve_name_recv(creq, state, &addr); + if (tevent_req_nterror(req, status)) { + return; + } - state->tree = smb2_tree_init(state->session, state, true); - if (composite_nomem(state->tree, c)) return; + if (state->ports == NULL) { + ports = default_ports; + } else { + ports = state->ports; + } - state->tcon.in.reserved = 0; - state->tcon.in.path = talloc_asprintf(state, "\\\\%s\\%s", - state->host, state->share); - if (composite_nomem(state->tcon.in.path, c)) return; - - req = smb2_tree_connect_send(state->tree, &state->tcon); - if (composite_nomem(req, c)) return; + creq = smbcli_sock_connect_send(state, addr, ports, + state->host, state->resolve_ctx, + state->ev, state->socket_options); + if (tevent_req_nomem(creq, req)) { + return; + } + creq->async.fn = smb2_connect_socket_done; + creq->async.private_data = req; +} + +static void smb2_connect_negprot_done(struct smb2_request *smb2req); - req->async.fn = continue_tcon; - req->async.private_data = c; +static void smb2_connect_socket_done(struct composite_context *creq) +{ + struct tevent_req *req = + talloc_get_type_abort(creq->async.private_data, + struct tevent_req); + struct smb2_connect_state *state = + tevent_req_data(req, + struct smb2_connect_state); + struct smbcli_socket *sock; + struct smb2_transport *transport; + struct smb2_request *smb2req; + NTSTATUS status; + uint16_t dialects[3] = { + SMB2_DIALECT_REVISION_000, + SMB2_DIALECT_REVISION_202, + SMB2_DIALECT_REVISION_210 + }; + + status = smbcli_sock_connect_recv(creq, state, &sock); + if (tevent_req_nterror(req, status)) { + return; + } + + transport = smb2_transport_init(sock, state, &state->options); + if (tevent_req_nomem(transport, req)) { + return; + } + + ZERO_STRUCT(state->negprot); + state->negprot.in.dialect_count = ARRAY_SIZE(dialects); + switch (transport->options.signing) { + case SMB_SIGNING_OFF: + state->negprot.in.security_mode = 0; + break; + case SMB_SIGNING_SUPPORTED: + case SMB_SIGNING_AUTO: + state->negprot.in.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED; + break; + case SMB_SIGNING_REQUIRED: + state->negprot.in.security_mode = + SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED; + break; + } + state->negprot.in.capabilities = 0; + unix_to_nt_time(&state->negprot.in.start_time, time(NULL)); + state->negprot.in.dialects = dialects; + + smb2req = smb2_negprot_send(transport, &state->negprot); + if (tevent_req_nomem(smb2req, req)) { + return; + } + smb2req->async.fn = smb2_connect_negprot_done; + smb2req->async.private_data = req; } -/* - continue after negprot reply -*/ -static void continue_negprot(struct smb2_request *req) +static void smb2_connect_session_done(struct tevent_req *subreq); + +static void smb2_connect_negprot_done(struct smb2_request *smb2req) { - struct composite_context *c = talloc_get_type(req->async.private_data, - struct composite_context); - struct smb2_connect_state *state = talloc_get_type(c->private_data, - struct smb2_connect_state); - struct smb2_transport *transport = req->transport; - struct composite_context *creq; + struct tevent_req *req = + talloc_get_type_abort(smb2req->async.private_data, + struct tevent_req); + struct smb2_connect_state *state = + tevent_req_data(req, + struct smb2_connect_state); + struct smb2_transport *transport = smb2req->transport; + struct tevent_req *subreq; + NTSTATUS status; - c->status = smb2_negprot_recv(req, c, &state->negprot); - if (!composite_is_ok(c)) return; + status = smb2_negprot_recv(smb2req, state, &state->negprot); + if (tevent_req_nterror(req, status)) { + return; + } transport->negotiate.secblob = state->negprot.out.secblob; talloc_steal(transport, transport->negotiate.secblob.data); @@ -115,7 +218,7 @@ static void continue_negprot(struct smb2_request *req) switch (transport->options.signing) { case SMB_SIGNING_OFF: if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) { - composite_error(c, NT_STATUS_ACCESS_DENIED); + tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); return; } transport->signing_required = false; @@ -138,179 +241,158 @@ static void continue_negprot(struct smb2_request *req) if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_ENABLED) { transport->signing_required = true; } else { - composite_error(c, NT_STATUS_ACCESS_DENIED); + tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); return; } break; } state->session = smb2_session_init(transport, state->gensec_settings, state, true); - if (composite_nomem(state->session, c)) return; - - creq = smb2_session_setup_spnego_send(state->session, state->credentials); - - composite_continue(c, creq, continue_session, c); -} - -/* - continue after a socket connect completes -*/ -static void continue_socket(struct composite_context *creq) -{ - struct composite_context *c = talloc_get_type(creq->async.private_data, - struct composite_context); - struct smb2_connect_state *state = talloc_get_type(c->private_data, - struct smb2_connect_state); - struct smbcli_socket *sock; - struct smb2_transport *transport; - struct smb2_request *req; - uint16_t dialects[3] = { - SMB2_DIALECT_REVISION_000, - SMB2_DIALECT_REVISION_202, - SMB2_DIALECT_REVISION_210 - }; - - c->status = smbcli_sock_connect_recv(creq, state, &sock); - if (!composite_is_ok(c)) return; - - transport = smb2_transport_init(sock, state, &state->options); - if (composite_nomem(transport, c)) return; - - ZERO_STRUCT(state->negprot); - state->negprot.in.dialect_count = sizeof(dialects) / sizeof(dialects[0]); - switch (transport->options.signing) { - case SMB_SIGNING_OFF: - state->negprot.in.security_mode = 0; - break; - case SMB_SIGNING_SUPPORTED: - case SMB_SIGNING_AUTO: - state->negprot.in.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED; - break; - case SMB_SIGNING_REQUIRED: - state->negprot.in.security_mode = - SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED; - break; + if (tevent_req_nomem(state->session, req)) { + return; } - state->negprot.in.capabilities = 0; - unix_to_nt_time(&state->negprot.in.start_time, time(NULL)); - state->negprot.in.dialects = dialects; - req = smb2_negprot_send(transport, &state->negprot); - if (composite_nomem(req, c)) return; - - req->async.fn = continue_negprot; - req->async.private_data = c; + subreq = smb2_session_setup_spnego_send(state, state->ev, + state->session, + state->credentials); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, smb2_connect_session_done, req); } +static void smb2_connect_tcon_done(struct smb2_request *smb2req); -/* - continue after a resolve finishes -*/ -static void continue_resolve(struct composite_context *creq) +static void smb2_connect_session_done(struct tevent_req *subreq) { - struct composite_context *c = talloc_get_type(creq->async.private_data, - struct composite_context); - struct smb2_connect_state *state = talloc_get_type(c->private_data, - struct smb2_connect_state); - const char *addr; - const char **ports; - const char *default_ports[] = { "445", NULL }; + struct tevent_req *req = + tevent_req_callback_data(subreq, + struct tevent_req); + struct smb2_connect_state *state = + tevent_req_data(req, + struct smb2_connect_state); + struct smb2_request *smb2req; + NTSTATUS status; - c->status = resolve_name_recv(creq, state, &addr); - if (!composite_is_ok(c)) return; + status = smb2_session_setup_spnego_recv(subreq); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } - if (state->ports == NULL) { - ports = default_ports; - } else { - ports = state->ports; + state->tree = smb2_tree_init(state->session, state, true); + if (tevent_req_nomem(state->tree, req)) { + return; } - creq = smbcli_sock_connect_send(state, addr, ports, state->host, state->resolve_ctx, c->event_ctx, state->socket_options); + state->tcon.in.reserved = 0; + state->tcon.in.path = talloc_asprintf(state, "\\\\%s\\%s", + state->host, state->share); + if (tevent_req_nomem(state->tcon.in.path, req)) { + return; + } - composite_continue(c, creq, continue_socket, c); + smb2req = smb2_tree_connect_send(state->tree, &state->tcon); + if (tevent_req_nomem(smb2req, req)) { + return; + } + smb2req->async.fn = smb2_connect_tcon_done; + smb2req->async.private_data = req; } -/* - a composite function that does a full negprot/sesssetup/tcon, returning - a connected smb2_tree - */ -struct composite_context *smb2_connect_send(TALLOC_CTX *mem_ctx, - const char *host, - const char **ports, - const char *share, - struct resolve_context *resolve_ctx, - struct cli_credentials *credentials, - struct tevent_context *ev, - struct smbcli_options *options, - const char *socket_options, - struct gensec_settings *gensec_settings) +static void smb2_connect_tcon_done(struct smb2_request *smb2req) { - struct composite_context *c; - struct smb2_connect_state *state; - struct nbt_name name; - struct composite_context *creq; - - c = composite_create(mem_ctx, ev); - if (c == NULL) return NULL; - - state = talloc(c, struct smb2_connect_state); - if (composite_nomem(state, c)) return c; - c->private_data = state; + struct tevent_req *req = + talloc_get_type_abort(smb2req->async.private_data, + struct tevent_req); + struct smb2_connect_state *state = + tevent_req_data(req, + struct smb2_connect_state); + NTSTATUS status; - state->credentials = credentials; - state->options = *options; - state->host = talloc_strdup(c, host); - if (composite_nomem(state->host, c)) return c; - state->ports = talloc_reference(state, ports); - state->share = talloc_strdup(c, share); - if (composite_nomem(state->share, c)) return c; - state->resolve_ctx = talloc_reference(state, resolve_ctx); - state->socket_options = talloc_reference(state, socket_options); - state->gensec_settings = talloc_reference(state, gensec_settings); + status = smb2_tree_connect_recv(smb2req, &state->tcon); + if (tevent_req_nterror(req, status)) { + return; + } - ZERO_STRUCT(name); - name.name = host; + state->tree->tid = state->tcon.out.tid; - creq = resolve_name_send(resolve_ctx, state, &name, c->event_ctx); - composite_continue(c, creq, continue_resolve, c); - return c; + tevent_req_done(req); } -/* - receive a connect reply -*/ -NTSTATUS smb2_connect_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, +NTSTATUS smb2_connect_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, struct smb2_tree **tree) { + struct smb2_connect_state *state = + tevent_req_data(req, + struct smb2_connect_state); NTSTATUS status; - struct smb2_connect_state *state = talloc_get_type(c->private_data, - struct smb2_connect_state); - status = composite_wait(c); - if (NT_STATUS_IS_OK(status)) { - *tree = talloc_steal(mem_ctx, state->tree); + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; } - talloc_free(c); - return status; + + *tree = talloc_move(mem_ctx, &state->tree); + + tevent_req_received(req); + return NT_STATUS_OK; } /* sync version of smb2_connect */ -NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx, - const char *host, const char **ports, - const char *share, +NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx, + const char *host, + const char **ports, + const char *share, struct resolve_context *resolve_ctx, struct cli_credentials *credentials, struct smb2_tree **tree, struct tevent_context *ev, struct smbcli_options *options, - const char *socket_options, - struct gensec_settings *gensec_settings) + const char *socket_options, + struct gensec_settings *gensec_settings) { - struct composite_context *c = smb2_connect_send(mem_ctx, host, ports, - share, resolve_ctx, - credentials, ev, options, - socket_options, - gensec_settings); - return smb2_connect_recv(c, mem_ctx, tree); + struct tevent_req *subreq; + NTSTATUS status; + bool ok; + TALLOC_CTX *frame = talloc_stackframe(); + + if (frame == NULL) { + return NT_STATUS_NO_MEMORY; + } + + subreq = smb2_connect_send(frame, + ev, + host, + ports, + share, + resolve_ctx, + credentials, + options, + socket_options, + gensec_settings); + if (subreq == NULL) { + TALLOC_FREE(frame); + return NT_STATUS_NO_MEMORY; + } + + ok = tevent_req_poll(subreq, ev); + if (!ok) { + status = map_nt_error_from_unix_common(errno); + TALLOC_FREE(frame); + return status; + } + + status = smb2_connect_recv(subreq, mem_ctx, tree); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); + return status; + } + + TALLOC_FREE(frame); + return NT_STATUS_OK; } |