summaryrefslogtreecommitdiff
path: root/source4/libcli/smb2
diff options
context:
space:
mode:
Diffstat (limited to 'source4/libcli/smb2')
-rw-r--r--source4/libcli/smb2/connect.c448
-rw-r--r--source4/libcli/smb2/session.c234
-rw-r--r--source4/libcli/smb2/wscript_build3
3 files changed, 407 insertions, 278 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;
}
diff --git a/source4/libcli/smb2/session.c b/source4/libcli/smb2/session.c
index 12479623e7..d46cdefc69 100644
--- a/source4/libcli/smb2/session.c
+++ b/source4/libcli/smb2/session.c
@@ -20,10 +20,11 @@
*/
#include "includes.h"
+#include <tevent.h>
+#include "lib/util/tevent_ntstatus.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/smb2/smb2.h"
#include "libcli/smb2/smb2_calls.h"
-#include "libcli/composite/composite.h"
#include "auth/gensec/gensec.h"
#include <unistd.h>
@@ -136,56 +137,133 @@ NTSTATUS smb2_session_setup(struct smb2_session *session,
return smb2_session_setup_recv(req, mem_ctx, io);
}
-
-struct smb2_session_state {
+struct smb2_session_setup_spnego_state {
struct smb2_session_setup io;
struct smb2_request *req;
NTSTATUS gensec_status;
};
+static void smb2_session_setup_spnego_handler(struct smb2_request *req);
+
+/*
+ a composite function that does a full SPNEGO session setup
+ */
+struct tevent_req *smb2_session_setup_spnego_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smb2_session *session,
+ struct cli_credentials *credentials)
+{
+ struct tevent_req *req;
+ struct smb2_session_setup_spnego_state *state;
+ const char *chosen_oid;
+ struct smb2_request *subreq;
+ NTSTATUS status;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2_session_setup_spnego_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ ZERO_STRUCT(state->io);
+ state->io.in.vc_number = 0;
+ if (session->transport->signing_required) {
+ state->io.in.security_mode =
+ SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED;
+ }
+ state->io.in.capabilities = 0;
+ state->io.in.channel = 0;
+ state->io.in.previous_sessionid = 0;
+
+ status = gensec_set_credentials(session->gensec, credentials);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ status = gensec_set_target_hostname(session->gensec,
+ session->transport->socket->hostname);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ status = gensec_set_target_service(session->gensec, "cifs");
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (session->transport->negotiate.secblob.length > 0) {
+ chosen_oid = GENSEC_OID_SPNEGO;
+ } else {
+ chosen_oid = GENSEC_OID_NTLMSSP;
+ }
+
+ status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ status = gensec_update(session->gensec, state,
+ session->transport->negotiate.secblob,
+ &state->io.in.secblob);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+ state->gensec_status = status;
+
+ subreq = smb2_session_setup_send(session, &state->io);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ subreq->async.fn = smb2_session_setup_spnego_handler;
+ subreq->async.private_data = req;
+
+ return req;
+}
+
/*
handle continuations of the spnego session setup
*/
-static void session_request_handler(struct smb2_request *req)
+static void smb2_session_setup_spnego_handler(struct smb2_request *subreq)
{
- struct composite_context *c = talloc_get_type(req->async.private_data,
- struct composite_context);
- struct smb2_session_state *state = talloc_get_type(c->private_data,
- struct smb2_session_state);
- struct smb2_session *session = req->session;
+ struct tevent_req *req =
+ talloc_get_type_abort(subreq->async.private_data,
+ struct tevent_req);
+ struct smb2_session_setup_spnego_state *state =
+ tevent_req_data(req,
+ struct smb2_session_setup_spnego_state);
+ struct smb2_session *session = subreq->session;
NTSTATUS session_key_err;
DATA_BLOB session_key;
NTSTATUS peer_status;
+ NTSTATUS status;
- c->status = smb2_session_setup_recv(req, c, &state->io);
- peer_status = c->status;
-
+ status = smb2_session_setup_recv(subreq, state, &state->io);
+ peer_status = status;
if (NT_STATUS_EQUAL(peer_status, NT_STATUS_MORE_PROCESSING_REQUIRED) ||
(NT_STATUS_IS_OK(peer_status) &&
NT_STATUS_EQUAL(state->gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED))) {
- c->status = gensec_update(session->gensec, c,
- state->io.out.secblob,
- &state->io.in.secblob);
- state->gensec_status = c->status;
-
+ status = gensec_update(session->gensec, state,
+ state->io.out.secblob,
+ &state->io.in.secblob);
+ state->gensec_status = status;
session->uid = state->io.out.uid;
}
- if (!NT_STATUS_IS_OK(c->status) &&
- !NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- composite_error(c, c->status);
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ tevent_req_nterror(req, status);
return;
}
if (NT_STATUS_EQUAL(peer_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- state->req = smb2_session_setup_send(session, &state->io);
- if (state->req == NULL) {
- composite_error(c, NT_STATUS_NO_MEMORY);
+ subreq = smb2_session_setup_send(session, &state->io);
+ if (tevent_req_nomem(subreq, req)) {
return;
}
- state->req->async.fn = session_request_handler;
- state->req->async.private_data = c;
+ subreq->async.fn = smb2_session_setup_spnego_handler;
+ subreq->async.private_data = req;
return;
}
@@ -198,84 +276,21 @@ static void session_request_handler(struct smb2_request *req)
if (session->session_key.length == 0) {
DEBUG(0,("Wrong session key length %u for SMB2 signing\n",
(unsigned)session->session_key.length));
- composite_error(c, NT_STATUS_ACCESS_DENIED);
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
return;
}
session->signing_active = true;
}
- composite_done(c);
-}
-
-/*
- a composite function that does a full SPNEGO session setup
- */
-struct composite_context *smb2_session_setup_spnego_send(struct smb2_session *session,
- struct cli_credentials *credentials)
-{
- struct composite_context *c;
- struct smb2_session_state *state;
- const char *chosen_oid;
-
- c = composite_create(session, session->transport->socket->event.ctx);
- if (c == NULL) return NULL;
-
- state = talloc(c, struct smb2_session_state);
- if (composite_nomem(state, c)) return c;
- c->private_data = state;
-
- ZERO_STRUCT(state->io);
- state->io.in.vc_number = 0;
- if (session->transport->signing_required) {
- state->io.in.security_mode =
- SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED;
- }
- state->io.in.capabilities = 0;
- state->io.in.channel = 0;
- state->io.in.previous_sessionid = 0;
-
- c->status = gensec_set_credentials(session->gensec, credentials);
- if (!composite_is_ok(c)) return c;
-
- c->status = gensec_set_target_hostname(session->gensec,
- session->transport->socket->hostname);
- if (!composite_is_ok(c)) return c;
-
- c->status = gensec_set_target_service(session->gensec, "cifs");
- if (!composite_is_ok(c)) return c;
-
- if (session->transport->negotiate.secblob.length > 0) {
- chosen_oid = GENSEC_OID_SPNEGO;
- } else {
- chosen_oid = GENSEC_OID_NTLMSSP;
- }
-
- c->status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
- if (!composite_is_ok(c)) return c;
-
- c->status = gensec_update(session->gensec, c,
- session->transport->negotiate.secblob,
- &state->io.in.secblob);
- if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- composite_error(c, c->status);
- return c;
- }
- state->gensec_status = c->status;
-
- state->req = smb2_session_setup_send(session, &state->io);
- composite_continue_smb2(c, state->req, session_request_handler, c);
- return c;
+ tevent_req_done(req);
}
/*
receive a composite session setup reply
*/
-NTSTATUS smb2_session_setup_spnego_recv(struct composite_context *c)
+NTSTATUS smb2_session_setup_spnego_recv(struct tevent_req *req)
{
- NTSTATUS status;
- status = composite_wait(c);
- talloc_free(c);
- return status;
+ return tevent_req_simple_recv_ntstatus(req);
}
/*
@@ -284,6 +299,37 @@ NTSTATUS smb2_session_setup_spnego_recv(struct composite_context *c)
NTSTATUS smb2_session_setup_spnego(struct smb2_session *session,
struct cli_credentials *credentials)
{
- struct composite_context *c = smb2_session_setup_spnego_send(session, credentials);
- return smb2_session_setup_spnego_recv(c);
+ struct tevent_req *subreq;
+ NTSTATUS status;
+ bool ok;
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev = session->transport->socket->event.ctx;
+
+ if (frame == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ subreq = smb2_session_setup_spnego_send(frame, ev,
+ session, credentials);
+ 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_session_setup_spnego_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
}
diff --git a/source4/libcli/smb2/wscript_build b/source4/libcli/smb2/wscript_build
index c39cf5fd39..5b5ac7d4e6 100644
--- a/source4/libcli/smb2/wscript_build
+++ b/source4/libcli/smb2/wscript_build
@@ -3,6 +3,7 @@
bld.SAMBA_SUBSYSTEM('LIBCLI_SMB2',
source='transport.c request.c negprot.c session.c tcon.c create.c close.c connect.c getinfo.c write.c read.c setinfo.c find.c ioctl.c logoff.c tdis.c flush.c lock.c notify.c cancel.c keepalive.c break.c util.c signing.c lease_break.c',
autoproto='smb2_proto.h',
- public_deps='LIBCLI_RAW LIBPACKET gensec'
+ deps='UTIL_TEVENT',
+ public_deps='LIBCLI_RAW LIBPACKET gensec tevent'
)