summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/libsmb/cliconnect.c333
1 files changed, 246 insertions, 87 deletions
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index 86cd7e749a..bdbc8f1e9d 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -524,18 +524,40 @@ static NTSTATUS cli_session_setup_plain(struct cli_state *cli,
@param workgroup The user's domain.
****************************************************************************/
-static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
- const char *pass, size_t passlen,
- const char *ntpass, size_t ntpasslen,
- const char *workgroup)
+struct cli_session_setup_nt1_state {
+ struct cli_state *cli;
+ uint16_t vwv[13];
+ DATA_BLOB response;
+ DATA_BLOB session_key;
+ const char *user;
+};
+
+static void cli_session_setup_nt1_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_session_setup_nt1_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct cli_state *cli, const char *user,
+ const char *pass, size_t passlen,
+ const char *ntpass, size_t ntpasslen,
+ const char *workgroup)
{
- uint32 capabilities = cli_session_setup_capabilities(cli);
+ struct tevent_req *req, *subreq;
+ struct cli_session_setup_nt1_state *state;
DATA_BLOB lm_response = data_blob_null;
DATA_BLOB nt_response = data_blob_null;
DATA_BLOB session_key = data_blob_null;
- NTSTATUS result;
- char *p;
- bool ok;
+ uint16_t *vwv;
+ uint8_t *bytes;
+ char *workgroup_upper;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_session_setup_nt1_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
+ state->user = user;
+ vwv = state->vwv;
if (passlen == 0) {
/* do nothing - guest login */
@@ -543,20 +565,35 @@ static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
if (lp_client_ntlmv2_auth()) {
DATA_BLOB server_chal;
DATA_BLOB names_blob;
- server_chal = data_blob(cli->secblob.data, MIN(cli->secblob.length, 8));
- /* note that the 'workgroup' here is a best guess - we don't know
- the server's domain at this point. The 'server name' is also
- dodgy...
- */
- names_blob = NTLMv2_generate_names_blob(NULL, cli->called.name, workgroup);
+ server_chal = data_blob(cli->secblob.data,
+ MIN(cli->secblob.length, 8));
+ if (tevent_req_nomem(server_chal.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * note that the 'workgroup' here is a best
+ * guess - we don't know the server's domain
+ * at this point. The 'server name' is also
+ * dodgy...
+ */
+ names_blob = NTLMv2_generate_names_blob(
+ NULL, cli->called.name, workgroup);
+
+ if (tevent_req_nomem(names_blob.data, req)) {
+ return tevent_req_post(req, ev);
+ }
- if (!SMBNTLMv2encrypt(NULL, user, workgroup, pass, &server_chal,
- &names_blob,
- &lm_response, &nt_response, NULL, &session_key)) {
+ if (!SMBNTLMv2encrypt(NULL, user, workgroup, pass,
+ &server_chal, &names_blob,
+ &lm_response, &nt_response,
+ NULL, &session_key)) {
data_blob_free(&names_blob);
data_blob_free(&server_chal);
- return NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(
+ req, NT_STATUS_ACCESS_DENIED);
+ return tevent_req_post(req, ev);
}
data_blob_free(&names_blob);
data_blob_free(&server_chal);
@@ -569,23 +606,50 @@ static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
nt_response = data_blob_null;
#else
nt_response = data_blob(NULL, 24);
- SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
+ if (tevent_req_nomem(nt_response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ SMBNTencrypt(pass, cli->secblob.data,
+ nt_response.data);
#endif
/* non encrypted password supplied. Ignore ntpass. */
if (lp_client_lanman_auth()) {
+
lm_response = data_blob(NULL, 24);
- if (!SMBencrypt(pass,cli->secblob.data, lm_response.data)) {
- /* Oops, the LM response is invalid, just put
- the NT response there instead */
+ if (tevent_req_nomem(lm_response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (!SMBencrypt(pass,cli->secblob.data,
+ lm_response.data)) {
+ /*
+ * Oops, the LM response is
+ * invalid, just put the NT
+ * response there instead
+ */
data_blob_free(&lm_response);
- lm_response = data_blob(nt_response.data, nt_response.length);
+ lm_response = data_blob(
+ nt_response.data,
+ nt_response.length);
}
} else {
- /* LM disabled, place NT# in LM field instead */
- lm_response = data_blob(nt_response.data, nt_response.length);
+ /*
+ * LM disabled, place NT# in LM field
+ * instead
+ */
+ lm_response = data_blob(
+ nt_response.data, nt_response.length);
+ }
+
+ if (tevent_req_nomem(lm_response.data, req)) {
+ return tevent_req_post(req, ev);
}
session_key = data_blob(NULL, 16);
+ if (tevent_req_nomem(session_key.data, req)) {
+ return tevent_req_post(req, ev);
+ }
#ifdef LANMAN_ONLY
E_deshash(pass, session_key.data);
memset(&session_key.data[8], '\0', 8);
@@ -600,94 +664,189 @@ static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
signing because we don't have original key */
lm_response = data_blob(pass, passlen);
+ if (tevent_req_nomem(lm_response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+
nt_response = data_blob(ntpass, ntpasslen);
+ if (tevent_req_nomem(nt_response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
}
- /* send a session setup command */
- memset(cli->outbuf,'\0',smb_size);
+#ifdef LANMAN_ONLY
+ state->response = data_blob_talloc(
+ state, lm_response.data, lm_response.length);
+#else
+ state->response = data_blob_talloc(
+ state, nt_response.data, nt_response.length);
+#endif
+ if (tevent_req_nomem(state->response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
- cli_set_message(cli->outbuf,13,0,True);
- SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
- cli_setup_packet(cli);
+ if (session_key.data) {
+ state->session_key = data_blob_talloc(
+ state, session_key.data, session_key.length);
+ if (tevent_req_nomem(state->session_key.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+ }
+ data_blob_free(&session_key);
- SCVAL(cli->outbuf,smb_vwv0,0xFF);
- SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
- SSVAL(cli->outbuf,smb_vwv3,2);
- SSVAL(cli->outbuf,smb_vwv4,cli->pid);
- SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
- SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
- SSVAL(cli->outbuf,smb_vwv8,nt_response.length);
- SIVAL(cli->outbuf,smb_vwv11,capabilities);
- p = smb_buf(cli->outbuf);
- if (lm_response.length) {
- memcpy(p,lm_response.data, lm_response.length); p += lm_response.length;
+ SCVAL(vwv+0, 0, 0xff);
+ SCVAL(vwv+0, 1, 0);
+ SSVAL(vwv+1, 0, 0);
+ SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
+ SSVAL(vwv+3, 0, 2);
+ SSVAL(vwv+4, 0, cli->pid);
+ SIVAL(vwv+5, 0, cli->sesskey);
+ SSVAL(vwv+7, 0, lm_response.length);
+ SSVAL(vwv+8, 0, nt_response.length);
+ SSVAL(vwv+9, 0, 0);
+ SSVAL(vwv+10, 0, 0);
+ SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli));
+
+ bytes = talloc_array(state, uint8_t,
+ lm_response.length + nt_response.length);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (lm_response.length != 0) {
+ memcpy(bytes, lm_response.data, lm_response.length);
}
- if (nt_response.length) {
- memcpy(p,nt_response.data, nt_response.length); p += nt_response.length;
+ if (nt_response.length != 0) {
+ memcpy(bytes + lm_response.length,
+ nt_response.data, nt_response.length);
}
- p += clistr_push(cli, p, user, -1, STR_TERMINATE);
+ data_blob_free(&lm_response);
+ data_blob_free(&nt_response);
- /* Upper case here might help some NTLMv2 implementations */
- p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
- p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
- p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
- cli_setup_bcc(cli, p);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ user, strlen(user)+1, NULL);
- if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
- result = cli_nt_error(cli);
- goto end;
+ /*
+ * Upper case here might help some NTLMv2 implementations
+ */
+ workgroup_upper = talloc_strdup_upper(talloc_tos(), workgroup);
+ if (tevent_req_nomem(workgroup_upper, req)) {
+ return tevent_req_post(req, ev);
}
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ workgroup_upper, strlen(workgroup_upper)+1,
+ NULL);
+ TALLOC_FREE(workgroup_upper);
- /* show_msg(cli->inbuf); */
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Unix", 5, NULL);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Samba", 6, NULL);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
- if (cli_is_error(cli)) {
- result = cli_nt_error(cli);
- goto end;
+ subreq = cli_smb_send(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
+ talloc_get_size(bytes), bytes);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
+ tevent_req_set_callback(subreq, cli_session_setup_nt1_done, req);
+ return req;
+}
-#ifdef LANMAN_ONLY
- ok = cli_simple_set_signing(cli, session_key, lm_response);
-#else
- ok = cli_simple_set_signing(cli, session_key, nt_response);
-#endif
- if (ok) {
- if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
- result = NT_STATUS_ACCESS_DENIED;
- goto end;
- }
+static void cli_session_setup_nt1_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_session_setup_nt1_state *state = tevent_req_data(
+ req, struct cli_session_setup_nt1_state);
+ struct cli_state *cli = state->cli;
+ uint32_t num_bytes;
+ uint8_t *in;
+ char *inbuf;
+ uint8_t *bytes;
+ uint8_t *p;
+ NTSTATUS status;
+
+ status = cli_smb_recv(subreq, state, &in, 0, NULL, NULL,
+ &num_bytes, &bytes);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
}
- /* use the returned vuid from now on */
- cli->vuid = SVAL(cli->inbuf,smb_uid);
+ inbuf = (char *)in;
+ p = bytes;
+
+ cli->vuid = SVAL(inbuf, smb_uid);
- p = smb_buf(cli->inbuf);
- p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
- -1, STR_TERMINATE);
- p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
- -1, STR_TERMINATE);
- p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
- -1, STR_TERMINATE);
+ p += clistr_pull(inbuf, cli->server_os, (char *)p, sizeof(fstring),
+ bytes+num_bytes-p, STR_TERMINATE);
+ p += clistr_pull(inbuf, cli->server_type, (char *)p, sizeof(fstring),
+ bytes+num_bytes-p, STR_TERMINATE);
+ p += clistr_pull(inbuf, cli->server_domain, (char *)p, sizeof(fstring),
+ bytes+num_bytes-p, STR_TERMINATE);
if (strstr(cli->server_type, "Samba")) {
cli->is_samba = True;
}
- result = cli_set_username(cli, user);
- if (!NT_STATUS_IS_OK(result)) {
- goto end;
+ status = cli_set_username(cli, state->user);
+ if (tevent_req_nterror(req, status)) {
+ return;
}
-
- if (session_key.data) {
+ if (cli_simple_set_signing(cli, state->session_key, state->response)
+ && !cli_check_sign_mac(cli, (char *)in, 1)) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+ if (state->session_key.data) {
/* Have plaintext orginal */
- cli_set_session_key(cli, session_key);
+ cli_set_session_key(cli, state->session_key);
}
+ tevent_req_done(req);
+}
- result = NT_STATUS_OK;
-end:
- data_blob_free(&lm_response);
- data_blob_free(&nt_response);
- data_blob_free(&session_key);
- return result;
+static NTSTATUS cli_session_setup_nt1_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
+ const char *pass, size_t passlen,
+ const char *ntpass, size_t ntpasslen,
+ const char *workgroup)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (cli_has_async_calls(cli)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_session_setup_nt1_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_nt1_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/* The following is calculated from :