client connect/disconnect routines
Copyright (C) Andrew Tridgell 1994-1998
Copyright (C) Andrew Bartlett 2001-2003
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
+#include "../libcli/auth/libcli_auth.h"
+#include "../libcli/auth/spnego.h"
+#include "smb_krb5.h"
+#include "ntlmssp.h"
static const struct {
int prot;
- const char *name;
-} prots[] = {
- {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
- {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
- {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
- {PROTOCOL_LANMAN1,"LANMAN1.0"},
- {PROTOCOL_LANMAN2,"LM1.2X002"},
- {PROTOCOL_LANMAN2,"DOS LANMAN2.1"},
- {PROTOCOL_LANMAN2,"LANMAN2.1"},
- {PROTOCOL_LANMAN2,"Samba"},
- {PROTOCOL_NT1,"NT LANMAN 1.0"},
- {PROTOCOL_NT1,"NT LM 0.12"},
- {-1,NULL}
+ const char name[24];
+} prots[10] = {
+ {PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"},
+ {PROTOCOL_COREPLUS, "MICROSOFT NETWORKS 1.03"},
+ {PROTOCOL_LANMAN1, "MICROSOFT NETWORKS 3.0"},
+ {PROTOCOL_LANMAN1, "LANMAN1.0"},
+ {PROTOCOL_LANMAN2, "LM1.2X002"},
+ {PROTOCOL_LANMAN2, "DOS LANMAN2.1"},
+ {PROTOCOL_LANMAN2, "LANMAN2.1"},
+ {PROTOCOL_LANMAN2, "Samba"},
+ {PROTOCOL_NT1, "NT LANMAN 1.0"},
+ {PROTOCOL_NT1, "NT LM 0.12"},
};
-static const char *star_smbserver_name = "*SMBSERVER";
+#define STAR_SMBSERVER "*SMBSERVER"
/**
* Set the user session key for a connection
{
DATA_BLOB session_key = data_blob_null;
DATA_BLOB lm_response = data_blob_null;
+ NTSTATUS status;
fstring pword;
char *p;
cli_set_message(cli->outbuf,10, 0, True);
SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
cli_setup_packet(cli);
-
+
SCVAL(cli->outbuf,smb_vwv0,0xFF);
SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
SSVAL(cli->outbuf,smb_vwv3,2);
if (cli_is_error(cli)) {
return cli_nt_error(cli);
}
-
+
/* use the returned vuid from now on */
cli->vuid = SVAL(cli->inbuf,smb_uid);
- fstrcpy(cli->user_name, user);
+ status = cli_set_username(cli, user);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
if (session_key.data) {
/* Have plaintext orginal */
Do a NT1 guest session setup.
****************************************************************************/
-static NTSTATUS cli_session_setup_guest(struct cli_state *cli)
+struct cli_session_setup_guest_state {
+ struct cli_state *cli;
+ uint16_t vwv[16];
+ struct iovec bytes;
+};
+
+static void cli_session_setup_guest_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_session_setup_guest_create(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ struct tevent_req **psmbreq)
{
- char *p;
- uint32 capabilities = cli_session_setup_capabilities(cli);
+ struct tevent_req *req, *subreq;
+ struct cli_session_setup_guest_state *state;
+ uint16_t *vwv;
+ uint8_t *bytes;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_session_setup_guest_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
+ vwv = state->vwv;
+
+ 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, 0);
+ SSVAL(vwv+8, 0, 0);
+ 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, 0);
+
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, /* username */
+ NULL);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, /* workgroup */
+ NULL);
+ 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 (bytes == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+
+ state->bytes.iov_base = (void *)bytes;
+ state->bytes.iov_len = talloc_get_size(bytes);
+
+ subreq = cli_smb_req_create(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
+ 1, &state->bytes);
+ if (subreq == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+ tevent_req_set_callback(subreq, cli_session_setup_guest_done, req);
+ *psmbreq = subreq;
+ return req;
+}
- memset(cli->outbuf, '\0', smb_size);
- cli_set_message(cli->outbuf,13,0,True);
- SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
- cli_setup_packet(cli);
-
- 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,0);
- SSVAL(cli->outbuf,smb_vwv8,0);
- SIVAL(cli->outbuf,smb_vwv11,capabilities);
- p = smb_buf(cli->outbuf);
- p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
- p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
- p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
- p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
- cli_setup_bcc(cli, p);
+struct tevent_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli)
+{
+ struct tevent_req *req, *subreq;
+ NTSTATUS status;
- if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
- return cli_nt_error(cli);
- }
-
- show_msg(cli->inbuf);
-
- if (cli_is_error(cli)) {
- return cli_nt_error(cli);
+ req = cli_session_setup_guest_create(mem_ctx, ev, cli, &subreq);
+ if (req == NULL) {
+ return NULL;
}
- cli->vuid = SVAL(cli->inbuf,smb_uid);
+ status = cli_smb_req_send(subreq);
+ if (NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
- p = smb_buf(cli->inbuf);
- p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
- p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
- p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
+static void cli_session_setup_guest_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_session_setup_guest_state *state = tevent_req_data(
+ req, struct cli_session_setup_guest_state);
+ struct cli_state *cli = state->cli;
+ uint32_t num_bytes;
+ char *inbuf;
+ uint8_t *bytes;
+ uint8_t *p;
+ NTSTATUS status;
+
+ status = cli_smb_recv(subreq, 0, NULL, NULL, &num_bytes, &bytes);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ inbuf = (char *)cli_smb_inbuf(subreq);
+ p = bytes;
+
+ cli->vuid = SVAL(inbuf, smb_uid);
+
+ 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;
}
- fstrcpy(cli->user_name, "");
+ TALLOC_FREE(subreq);
- return NT_STATUS_OK;
+ status = cli_set_username(cli, "");
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+NTSTATUS cli_session_setup_guest_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+static NTSTATUS cli_session_setup_guest(struct cli_state *cli)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_OK;
+
+ 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) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ req = cli_session_setup_guest_send(frame, ev, cli);
+ if (req == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ if (!tevent_req_poll(req, ev)) {
+ status = map_nt_error_from_unix(errno);
+ goto fail;
+ }
+
+ status = cli_session_setup_guest_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
{
uint32 capabilities = cli_session_setup_capabilities(cli);
char *p;
+ NTSTATUS status;
fstring lanman;
-
- fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
+
+ fstr_sprintf( lanman, "Samba %s", samba_version_string());
memset(cli->outbuf, '\0', smb_size);
cli_set_message(cli->outbuf,13,0,True);
SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
cli_setup_packet(cli);
-
+
SCVAL(cli->outbuf,smb_vwv0,0xFF);
SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
SSVAL(cli->outbuf,smb_vwv3,2);
SSVAL(cli->outbuf,smb_vwv8,0);
SIVAL(cli->outbuf,smb_vwv11,capabilities);
p = smb_buf(cli->outbuf);
-
+
/* check wether to send the ASCII or UNICODE version of the password */
-
+
if ( (capabilities & CAP_UNICODE) == 0 ) {
p += clistr_push(cli, p, pass, -1, STR_TERMINATE); /* password */
SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf)));
p += clistr_push(cli, p, pass, -1, STR_UNICODE|STR_TERMINATE); /* unicode password */
SSVAL(cli->outbuf,smb_vwv8,PTR_DIFF(p, smb_buf(cli->outbuf))-1);
}
-
+
p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
return cli_nt_error(cli);
}
-
+
show_msg(cli->inbuf);
-
+
if (cli_is_error(cli)) {
return cli_nt_error(cli);
}
cli->vuid = SVAL(cli->inbuf,smb_uid);
p = smb_buf(cli->inbuf);
- p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
- p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
- p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
- fstrcpy(cli->user_name, user);
-
+ 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);
+ status = cli_set_username(cli, user);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
if (strstr(cli->server_type, "Samba")) {
cli->is_samba = True;
}
DATA_BLOB session_key = data_blob_null;
NTSTATUS result;
char *p;
+ bool ok;
if (passlen == 0) {
/* do nothing - guest login */
the server's domain at this point. The 'server name' is also
dodgy...
*/
- names_blob = NTLMv2_generate_names_blob(cli->called.name, workgroup);
+ names_blob = NTLMv2_generate_names_blob(NULL, cli->called.name, workgroup);
- if (!SMBNTLMv2encrypt(user, workgroup, pass, &server_chal,
+ if (!SMBNTLMv2encrypt(NULL, user, workgroup, pass, &server_chal,
&names_blob,
- &lm_response, &nt_response, &session_key)) {
+ &lm_response, &nt_response, NULL, &session_key)) {
data_blob_free(&names_blob);
data_blob_free(&server_chal);
return NT_STATUS_ACCESS_DENIED;
E_deshash(pass, session_key.data);
memset(&session_key.data[8], '\0', 8);
#else
- SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
+ SMBsesskeygen_ntv1(nt_hash, session_key.data);
#endif
}
-#ifdef LANMAN_ONLY
- cli_simple_set_signing(cli, session_key, lm_response);
-#else
- cli_simple_set_signing(cli, session_key, nt_response);
-#endif
+ cli_temp_set_signing(cli);
} else {
/* pre-encrypted password supplied. Only used for
security=server, can't do
cli_set_message(cli->outbuf,13,0,True);
SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
cli_setup_packet(cli);
-
+
SCVAL(cli->outbuf,smb_vwv0,0xFF);
SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
SSVAL(cli->outbuf,smb_vwv3,2);
goto end;
}
+#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;
+ }
+ }
+
/* use the returned vuid from now on */
cli->vuid = SVAL(cli->inbuf,smb_uid);
-
+
p = smb_buf(cli->inbuf);
- p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
- p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
- p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
+ 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);
if (strstr(cli->server_type, "Samba")) {
cli->is_samba = True;
}
- fstrcpy(cli->user_name, user);
+ result = cli_set_username(cli, user);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto end;
+ }
if (session_key.data) {
/* Have plaintext orginal */
return result;
}
-/****************************************************************************
- Send a extended security session setup blob
-****************************************************************************/
-
-static bool cli_session_setup_blob_send(struct cli_state *cli, DATA_BLOB blob)
-{
- uint32 capabilities = cli_session_setup_capabilities(cli);
- char *p;
-
- capabilities |= CAP_EXTENDED_SECURITY;
-
- /* send a session setup command */
- memset(cli->outbuf,'\0',smb_size);
-
- cli_set_message(cli->outbuf,12,0,True);
- SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
-
- cli_setup_packet(cli);
-
- 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,1);
- SIVAL(cli->outbuf,smb_vwv5,0);
- SSVAL(cli->outbuf,smb_vwv7,blob.length);
- SIVAL(cli->outbuf,smb_vwv10,capabilities);
- p = smb_buf(cli->outbuf);
- memcpy(p, blob.data, blob.length);
- p += blob.length;
- p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
- p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
- cli_setup_bcc(cli, p);
- return cli_send_smb(cli);
-}
-
-/****************************************************************************
- Send a extended security session setup blob, returning a reply blob.
-****************************************************************************/
-
-static DATA_BLOB cli_session_setup_blob_receive(struct cli_state *cli)
-{
- DATA_BLOB blob2 = data_blob_null;
- char *p;
- size_t len;
-
- if (!cli_receive_smb(cli))
- return blob2;
-
- show_msg(cli->inbuf);
-
- if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
- NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- return blob2;
- }
-
- /* use the returned vuid from now on */
- cli->vuid = SVAL(cli->inbuf,smb_uid);
-
- p = smb_buf(cli->inbuf);
-
- blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
-
- p += blob2.length;
- p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
-
- /* w2k with kerberos doesn't properly null terminate this field */
- len = smb_bufrem(cli->inbuf, p);
- p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), len, 0);
-
- return blob2;
-}
-
-#ifdef HAVE_KRB5
-/****************************************************************************
- Send a extended security session setup blob, returning a reply blob.
-****************************************************************************/
-
/* The following is calculated from :
* (smb_size-4) = 35
* (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() )
#define BASE_SESSSETUP_BLOB_PACKET_SIZE (35 + 24 + 22)
-static bool cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob, DATA_BLOB session_key_krb5)
-{
- int32 remaining = blob.length;
- int32 cur = 0;
- DATA_BLOB send_blob = data_blob_null;
- int32 max_blob_size = 0;
- DATA_BLOB receive_blob = data_blob_null;
+struct cli_sesssetup_blob_state {
+ struct tevent_context *ev;
+ struct cli_state *cli;
+ DATA_BLOB blob;
+ uint16_t max_blob_size;
+ uint16_t vwv[12];
+ uint8_t *buf;
- if (cli->max_xmit < BASE_SESSSETUP_BLOB_PACKET_SIZE + 1) {
- DEBUG(0,("cli_session_setup_blob: cli->max_xmit too small "
- "(was %u, need minimum %u)\n",
- (unsigned int)cli->max_xmit,
- BASE_SESSSETUP_BLOB_PACKET_SIZE));
- cli_set_nt_error(cli, NT_STATUS_INVALID_PARAMETER);
- return False;
- }
+ NTSTATUS status;
+ char *inbuf;
+ DATA_BLOB ret_blob;
+};
- max_blob_size = cli->max_xmit - BASE_SESSSETUP_BLOB_PACKET_SIZE;
+static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
+ struct tevent_req **psubreq);
+static void cli_sesssetup_blob_done(struct tevent_req *subreq);
- while ( remaining > 0) {
- if (remaining >= max_blob_size) {
- send_blob.length = max_blob_size;
- remaining -= max_blob_size;
- } else {
- DATA_BLOB null_blob = data_blob_null;
+static struct tevent_req *cli_sesssetup_blob_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ DATA_BLOB blob)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_sesssetup_blob_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_sesssetup_blob_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->blob = blob;
+ state->cli = cli;
- send_blob.length = remaining;
- remaining = 0;
+ if (cli->max_xmit < BASE_SESSSETUP_BLOB_PACKET_SIZE + 1) {
+ DEBUG(1, ("cli_session_setup_blob: cli->max_xmit too small "
+ "(was %u, need minimum %u)\n",
+ (unsigned int)cli->max_xmit,
+ BASE_SESSSETUP_BLOB_PACKET_SIZE));
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+ state->max_blob_size =
+ MIN(cli->max_xmit - BASE_SESSSETUP_BLOB_PACKET_SIZE, 0xFFFF);
+
+ if (!cli_sesssetup_blob_next(state, &subreq)) {
+ tevent_req_nomem(NULL, req);
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
+ return req;
+}
- /* This is the last packet in the sequence - turn signing on. */
- cli_simple_set_signing(cli, session_key_krb5, null_blob);
- }
+static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
+ struct tevent_req **psubreq)
+{
+ struct tevent_req *subreq;
+ uint16_t thistime;
+
+ SCVAL(state->vwv+0, 0, 0xFF);
+ SCVAL(state->vwv+0, 1, 0);
+ SSVAL(state->vwv+1, 0, 0);
+ SSVAL(state->vwv+2, 0, CLI_BUFFER_SIZE);
+ SSVAL(state->vwv+3, 0, 2);
+ SSVAL(state->vwv+4, 0, 1);
+ SIVAL(state->vwv+5, 0, 0);
+
+ thistime = MIN(state->blob.length, state->max_blob_size);
+ SSVAL(state->vwv+7, 0, thistime);
+
+ SSVAL(state->vwv+8, 0, 0);
+ SSVAL(state->vwv+9, 0, 0);
+ SIVAL(state->vwv+10, 0,
+ cli_session_setup_capabilities(state->cli)
+ | CAP_EXTENDED_SECURITY);
+
+ state->buf = (uint8_t *)talloc_memdup(state, state->blob.data,
+ thistime);
+ if (state->buf == NULL) {
+ return false;
+ }
+ state->blob.data += thistime;
+ state->blob.length -= thistime;
+
+ state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli),
+ "Unix", 5, NULL);
+ state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli),
+ "Samba", 6, NULL);
+ if (state->buf == NULL) {
+ return false;
+ }
+ subreq = cli_smb_send(state, state->ev, state->cli, SMBsesssetupX, 0,
+ 12, state->vwv,
+ talloc_get_size(state->buf), state->buf);
+ if (subreq == NULL) {
+ return false;
+ }
+ *psubreq = subreq;
+ return true;
+}
- send_blob.data = &blob.data[cur];
- cur += send_blob.length;
+static void cli_sesssetup_blob_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_sesssetup_blob_state *state = tevent_req_data(
+ req, struct cli_sesssetup_blob_state);
+ struct cli_state *cli = state->cli;
+ uint8_t wct;
+ uint16_t *vwv;
+ uint32_t num_bytes;
+ uint8_t *bytes;
+ NTSTATUS status;
+ uint8_t *p;
+ uint16_t blob_length;
+
+ status = cli_smb_recv(subreq, 1, &wct, &vwv, &num_bytes, &bytes);
+ if (!NT_STATUS_IS_OK(status)
+ && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ state->status = status;
+ TALLOC_FREE(state->buf);
+
+ state->inbuf = (char *)cli_smb_inbuf(subreq);
+ cli->vuid = SVAL(state->inbuf, smb_uid);
+
+ blob_length = SVAL(vwv+3, 0);
+ if (blob_length > num_bytes) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ state->ret_blob = data_blob_const(bytes, blob_length);
+
+ p = bytes + blob_length;
+
+ p += clistr_pull(state->inbuf, cli->server_os,
+ (char *)p, sizeof(fstring),
+ bytes+num_bytes-p, STR_TERMINATE);
+ p += clistr_pull(state->inbuf, cli->server_type,
+ (char *)p, sizeof(fstring),
+ bytes+num_bytes-p, STR_TERMINATE);
+ p += clistr_pull(state->inbuf, cli->server_domain,
+ (char *)p, sizeof(fstring),
+ bytes+num_bytes-p, STR_TERMINATE);
- DEBUG(10, ("cli_session_setup_blob: Remaining (%u) sending (%u) current (%u)\n",
- (unsigned int)remaining,
- (unsigned int)send_blob.length,
- (unsigned int)cur ));
+ if (strstr(cli->server_type, "Samba")) {
+ cli->is_samba = True;
+ }
- if (!cli_session_setup_blob_send(cli, send_blob)) {
- DEBUG(0, ("cli_session_setup_blob: send failed\n"));
- return False;
+ if (state->blob.length != 0) {
+ TALLOC_FREE(subreq);
+ /*
+ * More to send
+ */
+ if (!cli_sesssetup_blob_next(state, &subreq)) {
+ tevent_req_nomem(NULL, req);
+ return;
}
+ tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
+ return;
+ }
+ tevent_req_done(req);
+}
- receive_blob = cli_session_setup_blob_receive(cli);
- data_blob_free(&receive_blob);
+static NTSTATUS cli_sesssetup_blob_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *pblob,
+ char **pinbuf)
+{
+ struct cli_sesssetup_blob_state *state = tevent_req_data(
+ req, struct cli_sesssetup_blob_state);
+ NTSTATUS status;
+ char *inbuf;
- if (cli_is_error(cli) &&
- !NT_STATUS_EQUAL( cli_get_nt_error(cli),
- NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- DEBUG(0, ("cli_session_setup_blob: receive failed "
- "(%s)\n", nt_errstr(cli_get_nt_error(cli))));
- cli->vuid = 0;
- return False;
- }
+ if (tevent_req_is_nterror(req, &status)) {
+ state->cli->vuid = 0;
+ return status;
}
- return True;
+ inbuf = talloc_move(mem_ctx, &state->inbuf);
+ if (pblob != NULL) {
+ *pblob = state->ret_blob;
+ }
+ if (pinbuf != NULL) {
+ *pinbuf = inbuf;
+ }
+ /* could be NT_STATUS_MORE_PROCESSING_REQUIRED */
+ return state->status;
}
+#ifdef HAVE_KRB5
+
/****************************************************************************
Use in-memory credentials cache
****************************************************************************/
Do a spnego/kerberos encrypted session setup.
****************************************************************************/
-static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup)
-{
+struct cli_session_setup_kerberos_state {
+ struct cli_state *cli;
DATA_BLOB negTokenTarg;
DATA_BLOB session_key_krb5;
+ ADS_STATUS ads_status;
+};
+
+static void cli_session_setup_kerberos_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_session_setup_kerberos_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
+ const char *principal, const char *workgroup)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_session_setup_kerberos_state *state;
int rc;
DEBUG(2,("Doing kerberos session setup\n"));
- /* generate the encapsulated kerberos5 ticket */
- rc = spnego_gen_negTokenTarg(principal, 0, &negTokenTarg, &session_key_krb5, 0, NULL);
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_session_setup_kerberos_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
+ state->ads_status = ADS_SUCCESS;
+
+ cli_temp_set_signing(cli);
+ /*
+ * Ok, this is cheated: spnego_gen_negTokenTarg can block if
+ * we have to acquire a ticket. To be fixed later :-)
+ */
+ rc = spnego_gen_negTokenTarg(principal, 0, &state->negTokenTarg,
+ &state->session_key_krb5, 0, NULL);
if (rc) {
- DEBUG(1, ("cli_session_setup_kerberos: spnego_gen_negTokenTarg failed: %s\n",
- error_message(rc)));
- return ADS_ERROR_KRB5(rc);
+ DEBUG(1, ("cli_session_setup_kerberos: "
+ "spnego_gen_negTokenTarg failed: %s\n",
+ error_message(rc)));
+ state->ads_status = ADS_ERROR_KRB5(rc);
+ tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+ return tevent_req_post(req, ev);
}
#if 0
- file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
+ file_save("negTokenTarg.dat", state->negTokenTarg.data,
+ state->negTokenTarg.length);
#endif
- if (!cli_session_setup_blob(cli, negTokenTarg, session_key_krb5)) {
- data_blob_free(&negTokenTarg);
- data_blob_free(&session_key_krb5);
- return ADS_ERROR_NT(cli_nt_error(cli));
+ subreq = cli_sesssetup_blob_send(state, ev, cli, state->negTokenTarg);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
+ tevent_req_set_callback(subreq, cli_session_setup_kerberos_done, req);
+ return req;
+}
- cli_set_session_key(cli, session_key_krb5);
+static void cli_session_setup_kerberos_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_session_setup_kerberos_state *state = tevent_req_data(
+ req, struct cli_session_setup_kerberos_state);
+ char *inbuf = NULL;
+ NTSTATUS status;
+
+ status = cli_sesssetup_blob_recv(subreq, talloc_tos(), NULL, &inbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ cli_set_session_key(state->cli, state->session_key_krb5);
+
+ if (cli_simple_set_signing(state->cli, state->session_key_krb5,
+ data_blob_null)
+ && !cli_check_sign_mac(state->cli, inbuf, 1)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+ TALLOC_FREE(subreq);
+ tevent_req_done(req);
+}
- data_blob_free(&negTokenTarg);
- data_blob_free(&session_key_krb5);
+static ADS_STATUS cli_session_setup_kerberos_recv(struct tevent_req *req)
+{
+ struct cli_session_setup_kerberos_state *state = tevent_req_data(
+ req, struct cli_session_setup_kerberos_state);
+ NTSTATUS status;
- if (cli_is_error(cli)) {
- if (NT_STATUS_IS_OK(cli_nt_error(cli))) {
- return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
- }
- }
- return ADS_ERROR_NT(cli_nt_error(cli));
+ if (tevent_req_is_nterror(req, &status)) {
+ return ADS_ERROR_NT(status);
+ }
+ return state->ads_status;
}
-#endif /* HAVE_KRB5 */
+static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli,
+ const char *principal,
+ const char *workgroup)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+
+ if (cli_has_async_calls(cli)) {
+ return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+ ev = tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_session_setup_kerberos_send(ev, ev, cli, principal,
+ workgroup);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll(req, ev)) {
+ status = ADS_ERROR_SYSTEM(errno);
+ goto fail;
+ }
+ status = cli_session_setup_kerberos_recv(req);
+fail:
+ TALLOC_FREE(ev);
+ return status;
+}
+#endif /* HAVE_KRB5 */
/****************************************************************************
Do a spnego/NTLMSSP encrypted session setup.
****************************************************************************/
-static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
- const char *pass, const char *domain)
-{
+struct cli_session_setup_ntlmssp_state {
+ struct tevent_context *ev;
+ struct cli_state *cli;
struct ntlmssp_state *ntlmssp_state;
- NTSTATUS nt_status;
- int turn = 1;
- DATA_BLOB msg1;
- DATA_BLOB blob = data_blob_null;
- DATA_BLOB blob_in = data_blob_null;
- DATA_BLOB blob_out = data_blob_null;
+ int turn;
+ DATA_BLOB blob_out;
+};
- cli_temp_set_signing(cli);
+static int cli_session_setup_ntlmssp_state_destructor(
+ struct cli_session_setup_ntlmssp_state *state)
+{
+ if (state->ntlmssp_state != NULL) {
+ ntlmssp_end(&state->ntlmssp_state);
+ }
+ return 0;
+}
- if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
- return nt_status;
+static void cli_session_setup_ntlmssp_done(struct tevent_req *req);
+
+static struct tevent_req *cli_session_setup_ntlmssp_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
+ const char *user, const char *pass, const char *domain)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_session_setup_ntlmssp_state *state;
+ NTSTATUS status;
+ DATA_BLOB blob_out;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_session_setup_ntlmssp_state);
+ if (req == NULL) {
+ return NULL;
}
- ntlmssp_want_feature(ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY);
+ state->ev = ev;
+ state->cli = cli;
+ state->turn = 1;
- if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) {
- return nt_status;
+ state->ntlmssp_state = NULL;
+ talloc_set_destructor(
+ state, cli_session_setup_ntlmssp_state_destructor);
+
+ cli_temp_set_signing(cli);
+
+ status = ntlmssp_client_start(&state->ntlmssp_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
}
- if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) {
- return nt_status;
+ ntlmssp_want_feature(state->ntlmssp_state,
+ NTLMSSP_FEATURE_SESSION_KEY);
+ status = ntlmssp_set_username(state->ntlmssp_state, user);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
}
- if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, pass))) {
- return nt_status;
+ status = ntlmssp_set_domain(state->ntlmssp_state, domain);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ status = ntlmssp_set_password(state->ntlmssp_state, pass);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ status = ntlmssp_update(state->ntlmssp_state, data_blob_null,
+ &blob_out);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ goto fail;
}
- do {
- nt_status = ntlmssp_update(ntlmssp_state,
- blob_in, &blob_out);
- data_blob_free(&blob_in);
- if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(nt_status)) {
- if (turn == 1) {
- /* and wrap it in a SPNEGO wrapper */
- msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
- } else {
- /* wrap it in SPNEGO */
- msg1 = spnego_gen_auth(blob_out);
- }
-
- /* now send that blob on its way */
- if (!cli_session_setup_blob_send(cli, msg1)) {
- DEBUG(3, ("Failed to send NTLMSSP/SPNEGO blob to server!\n"));
- nt_status = NT_STATUS_UNSUCCESSFUL;
- } else {
- blob = cli_session_setup_blob_receive(cli);
-
- nt_status = cli_nt_error(cli);
- if (cli_is_error(cli) && NT_STATUS_IS_OK(nt_status)) {
- if (cli->smb_rw_error == SMB_READ_BAD_SIG) {
- nt_status = NT_STATUS_ACCESS_DENIED;
- } else {
- nt_status = NT_STATUS_UNSUCCESSFUL;
- }
- }
- }
- data_blob_free(&msg1);
+ state->blob_out = gen_negTokenInit(OID_NTLMSSP, blob_out);
+ data_blob_free(&blob_out);
+
+ subreq = cli_sesssetup_blob_send(state, ev, cli, state->blob_out);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
+ return req;
+fail:
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+}
+
+static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
+ req, struct cli_session_setup_ntlmssp_state);
+ DATA_BLOB blob_in, msg_in, blob_out;
+ char *inbuf = NULL;
+ bool parse_ret;
+ NTSTATUS status;
+
+ status = cli_sesssetup_blob_recv(subreq, talloc_tos(), &blob_in,
+ &inbuf);
+ TALLOC_FREE(subreq);
+ data_blob_free(&state->blob_out);
+
+ if (NT_STATUS_IS_OK(status)) {
+ if (state->cli->server_domain[0] == '\0') {
+ fstrcpy(state->cli->server_domain,
+ state->ntlmssp_state->server_domain);
}
-
- if (!blob.length) {
- if (NT_STATUS_IS_OK(nt_status)) {
- nt_status = NT_STATUS_UNSUCCESSFUL;
- }
- } else if ((turn == 1) &&
- NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- DATA_BLOB tmp_blob = data_blob_null;
- /* the server might give us back two challenges */
- if (!spnego_parse_challenge(blob, &blob_in,
- &tmp_blob)) {
- DEBUG(3,("Failed to parse challenges\n"));
- nt_status = NT_STATUS_INVALID_PARAMETER;
- }
- data_blob_free(&tmp_blob);
- } else {
- if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP,
- &blob_in)) {
- DEBUG(3,("Failed to parse auth response\n"));
- if (NT_STATUS_IS_OK(nt_status)
- || NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED))
- nt_status = NT_STATUS_INVALID_PARAMETER;
- }
+ cli_set_session_key(
+ state->cli, state->ntlmssp_state->session_key);
+
+ if (cli_simple_set_signing(
+ state->cli, state->ntlmssp_state->session_key,
+ data_blob_null)
+ && !cli_check_sign_mac(state->cli, inbuf, 1)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
}
- data_blob_free(&blob);
- data_blob_free(&blob_out);
- turn++;
- } while (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED));
-
- data_blob_free(&blob_in);
+ TALLOC_FREE(subreq);
+ ntlmssp_end(&state->ntlmssp_state);
+ tevent_req_done(req);
+ return;
+ }
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
- if (NT_STATUS_IS_OK(nt_status)) {
+ if (blob_in.length == 0) {
+ tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+ return;
+ }
- DATA_BLOB key = data_blob(ntlmssp_state->session_key.data,
- ntlmssp_state->session_key.length);
- DATA_BLOB null_blob = data_blob_null;
- bool res;
+ if ((state->turn == 1)
+ && NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ DATA_BLOB tmp_blob = data_blob_null;
+ /* the server might give us back two challenges */
+ parse_ret = spnego_parse_challenge(blob_in, &msg_in,
+ &tmp_blob);
+ data_blob_free(&tmp_blob);
+ } else {
+ parse_ret = spnego_parse_auth_response(blob_in, status,
+ OID_NTLMSSP, &msg_in);
+ }
+ state->turn += 1;
+
+ if (!parse_ret) {
+ DEBUG(3,("Failed to parse auth response\n"));
+ if (NT_STATUS_IS_OK(status)
+ || NT_STATUS_EQUAL(status,
+ NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ tevent_req_nterror(
+ req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ }
- fstrcpy(cli->server_domain, ntlmssp_state->server_domain);
- cli_set_session_key(cli, ntlmssp_state->session_key);
+ status = ntlmssp_update(state->ntlmssp_state, msg_in, &blob_out);
- res = cli_simple_set_signing(cli, key, null_blob);
+ if (!NT_STATUS_IS_OK(status)
+ && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ TALLOC_FREE(subreq);
+ ntlmssp_end(&state->ntlmssp_state);
+ tevent_req_nterror(req, status);
+ return;
+ }
- data_blob_free(&key);
+ state->blob_out = spnego_gen_auth(blob_out);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nomem(state->blob_out.data, req)) {
+ return;
+ }
- if (res) {
-
- /* 'resign' the last message, so we get the right sequence numbers
- for checking the first reply from the server */
- cli_calculate_sign_mac(cli, cli->outbuf);
-
- if (!cli_check_sign_mac(cli, cli->inbuf)) {
- nt_status = NT_STATUS_ACCESS_DENIED;
- }
- }
+ subreq = cli_sesssetup_blob_send(state, state->ev, state->cli,
+ state->blob_out);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
}
+ tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
+}
- /* we have a reference conter on ntlmssp_state, if we are signing
- then the state will be kept by the signing engine */
+static NTSTATUS cli_session_setup_ntlmssp_recv(struct tevent_req *req)
+{
+ struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
+ req, struct cli_session_setup_ntlmssp_state);
+ NTSTATUS status;
- ntlmssp_end(&ntlmssp_state);
+ if (tevent_req_is_nterror(req, &status)) {
+ state->cli->vuid = 0;
+ return status;
+ }
+ return NT_STATUS_OK;
+}
- if (!NT_STATUS_IS_OK(nt_status)) {
- cli->vuid = 0;
+static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli,
+ const char *user,
+ const char *pass,
+ const char *domain)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (cli_has_async_calls(cli)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ev = tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
}
- return nt_status;
+ req = cli_session_setup_ntlmssp_send(ev, ev, cli, user, pass, domain);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_session_setup_ntlmssp_recv(req);
+fail:
+ TALLOC_FREE(ev);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
DATA_BLOB blob;
const char *p = NULL;
char *account = NULL;
+ NTSTATUS status;
DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)cli->secblob.length));
/* make sure the server understands kerberos */
for (i=0;OIDs[i];i++) {
- DEBUG(3,("got OID=%s\n", OIDs[i]));
+ if (i == 0)
+ DEBUG(3,("got OID=%s\n", OIDs[i]));
+ else
+ DEBUGADD(3,("got OID=%s\n", OIDs[i]));
if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
strcmp(OIDs[i], OID_KERBEROS5) == 0) {
cli->got_kerberos_mechanism = True;
DEBUG(3,("got principal=%s\n", principal ? principal : "<null>"));
- fstrcpy(cli->user_name, user);
+ status = cli_set_username(cli, user);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ADS_ERROR_NT(status);
+ }
#ifdef HAVE_KRB5
/* If password is set we reauthenticate to kerberos server
if (pass && *pass) {
int ret;
-
+
use_in_memory_ccache();
ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL);
-
+
if (ret){
TALLOC_FREE(principal);
DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
return ADS_ERROR_KRB5(ret);
}
}
-
+
/* If we get a bad principal, try to guess it if
we have a valid host NetBIOS name.
*/
if (principal == NULL &&
!is_ipaddress(cli->desthost) &&
- !strequal(star_smbserver_name,
+ !strequal(STAR_SMBSERVER,
cli->desthost)) {
char *realm = NULL;
char *machine = NULL;
Send a uloggoff.
*****************************************************************************/
-bool cli_ulogoff(struct cli_state *cli)
+struct cli_ulogoff_state {
+ struct cli_state *cli;
+ uint16_t vwv[2];
+};
+
+static void cli_ulogoff_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli)
{
- memset(cli->outbuf,'\0',smb_size);
- cli_set_message(cli->outbuf,2,0,True);
- SCVAL(cli->outbuf,smb_com,SMBulogoffX);
- cli_setup_packet(cli);
- SSVAL(cli->outbuf,smb_vwv0,0xFF);
- SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
+ struct tevent_req *req, *subreq;
+ struct cli_ulogoff_state *state;
- cli_send_smb(cli);
- if (!cli_receive_smb(cli))
- return False;
+ req = tevent_req_create(mem_ctx, &state, struct cli_ulogoff_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
- if (cli_is_error(cli)) {
- return False;
+ SCVAL(state->vwv+0, 0, 0xFF);
+ SCVAL(state->vwv+1, 0, 0);
+ SSVAL(state->vwv+2, 0, 0);
+
+ subreq = cli_smb_send(state, ev, cli, SMBulogoffX, 0, 2, state->vwv,
+ 0, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
+ tevent_req_set_callback(subreq, cli_ulogoff_done, req);
+ return req;
+}
+
+static void cli_ulogoff_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_ulogoff_state *state = tevent_req_data(
+ req, struct cli_ulogoff_state);
+ NTSTATUS status;
+
+ status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ state->cli->vuid = -1;
+ tevent_req_done(req);
+}
- cli->cnum = -1;
- return True;
+NTSTATUS cli_ulogoff_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_ulogoff(struct cli_state *cli)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (cli_has_async_calls(cli)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ev = tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_ulogoff_send(ev, ev, cli);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_ulogoff_recv(req);
+fail:
+ TALLOC_FREE(ev);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
Send a tconX.
****************************************************************************/
-bool cli_send_tconX(struct cli_state *cli,
- const char *share, const char *dev, const char *pass, int passlen)
+struct cli_tcon_andx_state {
+ struct cli_state *cli;
+ uint16_t vwv[4];
+ struct iovec bytes;
+};
+
+static void cli_tcon_andx_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *share, const char *dev,
+ const char *pass, int passlen,
+ struct tevent_req **psmbreq)
{
- fstring fullshare, pword;
- char *p;
- memset(cli->outbuf,'\0',smb_size);
- memset(cli->inbuf,'\0',smb_size);
+ struct tevent_req *req, *subreq;
+ struct cli_tcon_andx_state *state;
+ fstring pword;
+ uint16_t *vwv;
+ char *tmp = NULL;
+ uint8_t *bytes;
+
+ *psmbreq = NULL;
+
+ req = tevent_req_create(mem_ctx, &state, struct cli_tcon_andx_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
+ vwv = state->vwv;
fstrcpy(cli->share, share);
if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
passlen = 1;
pass = "";
- } else if (!pass) {
- DEBUG(1, ("Server not using user level security and no password supplied.\n"));
- return False;
+ } else if (pass == NULL) {
+ DEBUG(1, ("Server not using user level security and no "
+ "password supplied.\n"));
+ goto access_denied;
}
if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) &&
DEBUG(1, ("Server requested LANMAN password "
"(share-level security) but "
"'client lanman auth' is disabled\n"));
- return False;
+ goto access_denied;
}
/*
- * Non-encrypted passwords - convert to DOS codepage before encryption.
+ * Non-encrypted passwords - convert to DOS codepage before
+ * encryption.
*/
passlen = 24;
- SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
+ SMBencrypt(pass, cli->secblob.data, (uchar *)pword);
} else {
- if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
+ if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL
+ |NEGOTIATE_SECURITY_CHALLENGE_RESPONSE))
+ == 0) {
if (!lp_client_plaintext_auth() && (*pass)) {
DEBUG(1, ("Server requested plaintext "
"password but 'client plaintext "
"auth' is disabled\n"));
- return False;
+ goto access_denied;
}
/*
- * Non-encrypted passwords - convert to DOS codepage before using.
+ * Non-encrypted passwords - convert to DOS codepage
+ * before using.
*/
- passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
-
+ passlen = clistr_push(cli, pword, pass, sizeof(pword),
+ STR_TERMINATE);
+ if (passlen == -1) {
+ DEBUG(1, ("clistr_push(pword) failed\n"));
+ goto access_denied;
+ }
} else {
if (passlen) {
memcpy(pword, pass, passlen);
}
}
- slprintf(fullshare, sizeof(fullshare)-1,
- "\\\\%s\\%s", cli->desthost, share);
+ SCVAL(vwv+0, 0, 0xFF);
+ SCVAL(vwv+0, 1, 0);
+ SSVAL(vwv+1, 0, 0);
+ SSVAL(vwv+2, 0, TCONX_FLAG_EXTENDED_RESPONSE);
+ SSVAL(vwv+3, 0, passlen);
- cli_set_message(cli->outbuf,4, 0, True);
- SCVAL(cli->outbuf,smb_com,SMBtconX);
- cli_setup_packet(cli);
+ if (passlen) {
+ bytes = (uint8_t *)talloc_memdup(state, pword, passlen);
+ } else {
+ bytes = talloc_array(state, uint8_t, 0);
+ }
- SSVAL(cli->outbuf,smb_vwv0,0xFF);
- SSVAL(cli->outbuf,smb_vwv2,TCONX_FLAG_EXTENDED_RESPONSE);
- SSVAL(cli->outbuf,smb_vwv3,passlen);
+ /*
+ * Add the sharename
+ */
+ tmp = talloc_asprintf_strupper_m(talloc_tos(), "\\\\%s\\%s",
+ cli->desthost, share);
+ if (tmp == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1,
+ NULL);
+ TALLOC_FREE(tmp);
- p = smb_buf(cli->outbuf);
- if (passlen) {
- memcpy(p,pword,passlen);
+ /*
+ * Add the devicetype
+ */
+ tmp = talloc_strdup_upper(talloc_tos(), dev);
+ if (tmp == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
}
- p += passlen;
- p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
- p += clistr_push(cli, p, dev, -1, STR_TERMINATE |STR_UPPER | STR_ASCII);
+ bytes = smb_bytes_push_str(bytes, false, tmp, strlen(tmp)+1, NULL);
+ TALLOC_FREE(tmp);
- cli_setup_bcc(cli, p);
+ if (bytes == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
- cli_send_smb(cli);
- if (!cli_receive_smb(cli))
- return False;
+ state->bytes.iov_base = (void *)bytes;
+ state->bytes.iov_len = talloc_get_size(bytes);
- if (cli_is_error(cli))
- return False;
+ subreq = cli_smb_req_create(state, ev, cli, SMBtconX, 0, 4, vwv,
+ 1, &state->bytes);
+ if (subreq == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+ tevent_req_set_callback(subreq, cli_tcon_andx_done, req);
+ *psmbreq = subreq;
+ return req;
+
+ access_denied:
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return tevent_req_post(req, ev);
+}
+
+struct tevent_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *share, const char *dev,
+ const char *pass, int passlen)
+{
+ struct tevent_req *req, *subreq;
+ NTSTATUS status;
- clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
+ req = cli_tcon_andx_create(mem_ctx, ev, cli, share, dev, pass, passlen,
+ &subreq);
+ if (req == NULL) {
+ return NULL;
+ }
+ if (subreq == NULL) {
+ return req;
+ }
+ status = cli_smb_req_send(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
- if (cli->protocol >= PROTOCOL_NT1 &&
- smb_buflen(cli->inbuf) == 3) {
+static void cli_tcon_andx_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_tcon_andx_state *state = tevent_req_data(
+ req, struct cli_tcon_andx_state);
+ struct cli_state *cli = state->cli;
+ char *inbuf = (char *)cli_smb_inbuf(subreq);
+ uint8_t wct;
+ uint16_t *vwv;
+ uint32_t num_bytes;
+ uint8_t *bytes;
+ NTSTATUS status;
+
+ status = cli_smb_recv(subreq, 0, &wct, &vwv, &num_bytes, &bytes);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ clistr_pull(inbuf, cli->dev, bytes, sizeof(fstring), num_bytes,
+ STR_TERMINATE|STR_ASCII);
+
+ if ((cli->protocol >= PROTOCOL_NT1) && (num_bytes == 3)) {
/* almost certainly win95 - enable bug fixes */
cli->win95 = True;
}
-
- /* Make sure that we have the optional support 16-bit field. WCT > 2 */
- /* Avoids issues when connecting to Win9x boxes sharing files */
- cli->dfsroot = False;
- if ( (CVAL(cli->inbuf, smb_wct))>2 && cli->protocol >= PROTOCOL_LANMAN2 )
- cli->dfsroot = (SVAL( cli->inbuf, smb_vwv2 ) & SMB_SHARE_IN_DFS) ? True : False;
+ /*
+ * Make sure that we have the optional support 16-bit field. WCT > 2.
+ * Avoids issues when connecting to Win9x boxes sharing files
+ */
- cli->cnum = SVAL(cli->inbuf,smb_tid);
- return True;
+ cli->dfsroot = false;
+
+ if ((wct > 2) && (cli->protocol >= PROTOCOL_LANMAN2)) {
+ cli->dfsroot = ((SVAL(vwv+2, 0) & SMB_SHARE_IN_DFS) != 0);
+ }
+
+ cli->cnum = SVAL(inbuf,smb_tid);
+ tevent_req_done(req);
+}
+
+NTSTATUS cli_tcon_andx_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share,
+ const char *dev, const char *pass, int passlen)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_OK;
+
+ 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) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ req = cli_tcon_andx_send(frame, ev, cli, share, dev, pass, passlen);
+ if (req == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ if (!tevent_req_poll(req, ev)) {
+ status = map_nt_error_from_unix(errno);
+ goto fail;
+ }
+
+ status = cli_tcon_andx_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
Send a tree disconnect.
****************************************************************************/
-bool cli_tdis(struct cli_state *cli)
+struct cli_tdis_state {
+ struct cli_state *cli;
+};
+
+static void cli_tdis_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli)
{
- memset(cli->outbuf,'\0',smb_size);
- cli_set_message(cli->outbuf,0,0,True);
- SCVAL(cli->outbuf,smb_com,SMBtdis);
- SSVAL(cli->outbuf,smb_tid,cli->cnum);
- cli_setup_packet(cli);
-
- cli_send_smb(cli);
- if (!cli_receive_smb(cli))
- return False;
-
- if (cli_is_error(cli)) {
- return False;
+ struct tevent_req *req, *subreq;
+ struct cli_tdis_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct cli_tdis_state);
+ if (req == NULL) {
+ return NULL;
}
+ state->cli = cli;
- cli->cnum = -1;
- return True;
+ subreq = cli_smb_send(state, ev, cli, SMBtdis, 0, 0, NULL, 0, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_tdis_done, req);
+ return req;
+}
+
+static void cli_tdis_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_tdis_state *state = tevent_req_data(
+ req, struct cli_tdis_state);
+ NTSTATUS status;
+
+ status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ state->cli->cnum = -1;
+ tevent_req_done(req);
+}
+
+NTSTATUS cli_tdis_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_tdis(struct cli_state *cli)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (cli_has_async_calls(cli)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ev = tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_tdis_send(ev, ev, cli);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_tdis_recv(req);
+fail:
+ TALLOC_FREE(ev);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
Send a negprot command.
****************************************************************************/
-void cli_negprot_send(struct cli_state *cli)
+void cli_negprot_sendsync(struct cli_state *cli)
{
char *p;
int numprots;
cli_set_message(cli->outbuf,0,0,True);
p = smb_buf(cli->outbuf);
- for (numprots=0;
- prots[numprots].name && prots[numprots].prot<=cli->protocol;
- numprots++) {
+ for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
+ if (prots[numprots].prot > cli->protocol) {
+ break;
+ }
*p++ = 2;
p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
}
Send a negprot command.
****************************************************************************/
-bool cli_negprot(struct cli_state *cli)
+struct cli_negprot_state {
+ struct cli_state *cli;
+};
+
+static void cli_negprot_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_negprot_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli)
{
- char *p;
+ struct tevent_req *req, *subreq;
+ struct cli_negprot_state *state;
+ uint8_t *bytes = NULL;
int numprots;
- int plength;
+ uint16_t cnum;
+
+ req = tevent_req_create(mem_ctx, &state, struct cli_negprot_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
if (cli->protocol < PROTOCOL_NT1)
cli->use_spnego = False;
- memset(cli->outbuf,'\0',smb_size);
-
/* setup the protocol strings */
- for (plength=0,numprots=0;
- prots[numprots].name && prots[numprots].prot<=cli->protocol;
- numprots++)
- plength += strlen(prots[numprots].name)+2;
-
- cli_set_message(cli->outbuf,0,plength,True);
-
- p = smb_buf(cli->outbuf);
- for (numprots=0;
- prots[numprots].name && prots[numprots].prot<=cli->protocol;
- numprots++) {
- *p++ = 2;
- p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
+ for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
+ uint8_t c = 2;
+ if (prots[numprots].prot > cli->protocol) {
+ break;
+ }
+ bytes = (uint8_t *)talloc_append_blob(
+ state, bytes, data_blob_const(&c, sizeof(c)));
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+ bytes = smb_bytes_push_str(bytes, false,
+ prots[numprots].name,
+ strlen(prots[numprots].name)+1,
+ NULL);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
}
- SCVAL(cli->outbuf,smb_com,SMBnegprot);
- cli_setup_packet(cli);
+ cnum = cli->cnum;
- SCVAL(smb_buf(cli->outbuf),0,2);
+ cli->cnum = 0;
+ subreq = cli_smb_send(state, ev, cli, SMBnegprot, 0, 0, NULL,
+ talloc_get_size(bytes), bytes);
+ cli->cnum = cnum;
- cli_send_smb(cli);
- if (!cli_receive_smb(cli))
- return False;
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_negprot_done, req);
+ return req;
+}
- show_msg(cli->inbuf);
+static void cli_negprot_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_negprot_state *state = tevent_req_data(
+ req, struct cli_negprot_state);
+ struct cli_state *cli = state->cli;
+ uint8_t wct;
+ uint16_t *vwv;
+ uint32_t num_bytes;
+ uint8_t *bytes;
+ NTSTATUS status;
+ uint16_t protnum;
+
+ status = cli_smb_recv(subreq, 1, &wct, &vwv, &num_bytes, &bytes);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ protnum = SVAL(vwv, 0);
- if (cli_is_error(cli) ||
- ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
- return(False);
+ if ((protnum >= ARRAY_SIZE(prots))
+ || (prots[protnum].prot > cli->protocol)) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
}
- cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
+ cli->protocol = prots[protnum].prot;
- if ((cli->protocol < PROTOCOL_NT1) && cli->sign_info.mandatory_signing) {
+ if ((cli->protocol < PROTOCOL_NT1) &&
+ client_is_signing_mandatory(cli)) {
DEBUG(0,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n"));
- return False;
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
}
if (cli->protocol >= PROTOCOL_NT1) {
struct timespec ts;
+ bool negotiated_smb_signing = false;
+
/* NT protocol */
- cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
- cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
- cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
- cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
- cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
+ cli->sec_mode = CVAL(vwv + 1, 0);
+ cli->max_mux = SVAL(vwv + 1, 1);
+ cli->max_xmit = IVAL(vwv + 3, 1);
+ cli->sesskey = IVAL(vwv + 7, 1);
+ cli->serverzone = SVALS(vwv + 15, 1);
cli->serverzone *= 60;
/* this time arrives in real GMT */
- ts = interpret_long_date(cli->inbuf+smb_vwv11+1);
+ ts = interpret_long_date(((char *)(vwv+11))+1);
cli->servertime = ts.tv_sec;
- cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
- cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
+ cli->secblob = data_blob(bytes, num_bytes);
+ cli->capabilities = IVAL(vwv + 9, 1);
if (cli->capabilities & CAP_RAW_MODE) {
cli->readbraw_supported = True;
cli->writebraw_supported = True;
/* work out if they sent us a workgroup */
if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
smb_buflen(cli->inbuf) > 8) {
- clistr_pull(cli, cli->server_domain,
- smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
- smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
+ clistr_pull(cli->inbuf, cli->server_domain,
+ bytes+8, sizeof(cli->server_domain),
+ num_bytes-8,
+ STR_UNICODE|STR_NOALIGN);
}
/*
if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
/* Fail if server says signing is mandatory and we don't want to support it. */
- if (!cli->sign_info.allow_smb_signing) {
+ if (!client_is_signing_allowed(cli)) {
DEBUG(0,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
- return False;
+ tevent_req_nterror(req,
+ NT_STATUS_ACCESS_DENIED);
+ return;
}
- cli->sign_info.negotiated_smb_signing = True;
- cli->sign_info.mandatory_signing = True;
- } else if (cli->sign_info.mandatory_signing && cli->sign_info.allow_smb_signing) {
+ negotiated_smb_signing = true;
+ } else if (client_is_signing_mandatory(cli) && client_is_signing_allowed(cli)) {
/* Fail if client says signing is mandatory and the server doesn't support it. */
if (!(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) {
DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n"));
- return False;
+ tevent_req_nterror(req,
+ NT_STATUS_ACCESS_DENIED);
+ return;
}
- cli->sign_info.negotiated_smb_signing = True;
- cli->sign_info.mandatory_signing = True;
+ negotiated_smb_signing = true;
} else if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
- cli->sign_info.negotiated_smb_signing = True;
+ negotiated_smb_signing = true;
+ }
+
+ if (negotiated_smb_signing) {
+ cli_set_signing_negotiated(cli);
}
if (cli->capabilities & (CAP_LARGE_READX|CAP_LARGE_WRITEX)) {
} else if (cli->protocol >= PROTOCOL_LANMAN1) {
cli->use_spnego = False;
- cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
- cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
- cli->max_mux = SVAL(cli->inbuf, smb_vwv3);
- cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
- cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
+ cli->sec_mode = SVAL(vwv + 1, 0);
+ cli->max_xmit = SVAL(vwv + 2, 0);
+ cli->max_mux = SVAL(vwv + 3, 0);
+ cli->sesskey = IVAL(vwv + 6, 0);
+ cli->serverzone = SVALS(vwv + 10, 0);
cli->serverzone *= 60;
/* this time is converted to GMT by make_unix_date */
- cli->servertime = cli_make_unix_date(cli,cli->inbuf+smb_vwv8);
- cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
- cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
- cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
+ cli->servertime = cli_make_unix_date(
+ cli, (char *)(vwv + 8));
+ cli->readbraw_supported = ((SVAL(vwv + 5, 0) & 0x1) != 0);
+ cli->writebraw_supported = ((SVAL(vwv + 5, 0) & 0x2) != 0);
+ cli->secblob = data_blob(bytes, num_bytes);
} else {
/* the old core protocol */
cli->use_spnego = False;
if (getenv("CLI_FORCE_ASCII"))
cli->capabilities &= ~CAP_UNICODE;
- return True;
+ tevent_req_done(req);
+}
+
+NTSTATUS cli_negprot_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_negprot(struct cli_state *cli)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_OK;
+
+ 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) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ req = cli_negprot_send(frame, ev, cli);
+ if (req == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ if (!tevent_req_poll(req, ev)) {
+ status = map_nt_error_from_unix(errno);
+ goto fail;
+ }
+
+ status = cli_negprot_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
{
char *p;
int len = 4;
+ char *tmp;
+
+ /* 445 doesn't have session request */
+ if (cli->port == 445)
+ return True;
memcpy(&(cli->calling), calling, sizeof(*calling));
memcpy(&(cli->called ), called , sizeof(*called ));
-
+
/* put in the destination name */
+
+ tmp = name_mangle(talloc_tos(), cli->called.name,
+ cli->called.name_type);
+ if (tmp == NULL) {
+ return false;
+ }
+
p = cli->outbuf+len;
- name_mangle(cli->called .name, p, cli->called .name_type);
- len += name_len(p);
+ memcpy(p, tmp, name_len(tmp));
+ len += name_len(tmp);
+ TALLOC_FREE(tmp);
/* and my name */
- p = cli->outbuf+len;
- name_mangle(cli->calling.name, p, cli->calling.name_type);
- len += name_len(p);
- /* 445 doesn't have session request */
- if (cli->port == 445)
- return True;
+ tmp = name_mangle(talloc_tos(), cli->calling.name,
+ cli->calling.name_type);
+ if (tmp == NULL) {
+ return false;
+ }
+
+ p = cli->outbuf+len;
+ memcpy(p, tmp, name_len(tmp));
+ len += name_len(tmp);
+ TALLOC_FREE(tmp);
/* send a session request (RFC 1002) */
/* setup the packet length
*/
uint16_t port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
struct in_addr dest_ip;
+ NTSTATUS status;
/* SESSION RETARGET */
putip((char *)&dest_ip,cli->inbuf+4);
in_addr_to_sockaddr_storage(&cli->dest_ss, dest_ip);
- cli->fd = open_socket_out(SOCK_STREAM,
- &cli->dest_ss,
- port,
- LONG_CONNECT_TIMEOUT);
- if (cli->fd == -1)
+ status = open_socket_out(&cli->dest_ss, port,
+ LONG_CONNECT_TIMEOUT, &cli->fd);
+ if (!NT_STATUS_IS_OK(status)) {
return False;
+ }
DEBUG(3,("Retargeted\n"));
return(True);
}
+struct fd_struct {
+ int fd;
+};
+
+static void smb_sock_connected(struct tevent_req *req)
+{
+ struct fd_struct *pfd = tevent_req_callback_data(
+ req, struct fd_struct);
+ int fd;
+ NTSTATUS status;
+
+ status = open_socket_out_defer_recv(req, &fd);
+ if (NT_STATUS_IS_OK(status)) {
+ pfd->fd = fd;
+ }
+}
+
+static NTSTATUS open_smb_socket(const struct sockaddr_storage *pss,
+ uint16_t *port, int timeout, int *pfd)
+{
+ struct event_context *ev;
+ struct tevent_req *r139, *r445;
+ struct fd_struct *fd139, *fd445;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (*port != 0) {
+ return open_socket_out(pss, *port, timeout, pfd);
+ }
+
+ ev = event_context_init(talloc_tos());
+ if (ev == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ fd139 = talloc(ev, struct fd_struct);
+ if (fd139 == NULL) {
+ goto done;
+ }
+ fd139->fd = -1;
+
+ fd445 = talloc(ev, struct fd_struct);
+ if (fd445 == NULL) {
+ goto done;
+ }
+ fd445->fd = -1;
+
+ r445 = open_socket_out_defer_send(ev, ev, timeval_set(0, 0),
+ pss, 445, timeout);
+ r139 = open_socket_out_defer_send(ev, ev, timeval_set(0, 3000),
+ pss, 139, timeout);
+ if ((r445 == NULL) || (r139 == NULL)) {
+ goto done;
+ }
+ tevent_req_set_callback(r445, smb_sock_connected, fd445);
+ tevent_req_set_callback(r139, smb_sock_connected, fd139);
+
+ while ((fd445->fd == -1) && (fd139->fd == -1)
+ && (tevent_req_is_in_progress(r139)
+ || tevent_req_is_in_progress(r445))) {
+ event_loop_once(ev);
+ }
+
+ if ((fd139->fd != -1) && (fd445->fd != -1)) {
+ close(fd139->fd);
+ fd139->fd = -1;
+ }
+
+ if (fd445->fd != -1) {
+ *port = 445;
+ *pfd = fd445->fd;
+ status = NT_STATUS_OK;
+ goto done;
+ }
+ if (fd139->fd != -1) {
+ *port = 139;
+ *pfd = fd139->fd;
+ status = NT_STATUS_OK;
+ goto done;
+ }
+
+ status = open_socket_out_defer_recv(r445, &fd445->fd);
+ done:
+ TALLOC_FREE(ev);
+ return status;
+}
+
/****************************************************************************
Open the client sockets.
****************************************************************************/
/* reasonable default hostname */
if (!host) {
- host = star_smbserver_name;
+ host = STAR_SMBSERVER;
}
fstrcpy(cli->desthost, host);
if (getenv("LIBSMB_PROG")) {
cli->fd = sock_exec(getenv("LIBSMB_PROG"));
} else {
- /* try 445 first, then 139 */
- uint16_t port = cli->port?cli->port:445;
- cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ss,
- port, cli->timeout);
- if (cli->fd == -1 && cli->port == 0) {
- port = 139;
- cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ss,
- port, cli->timeout);
- }
- if (cli->fd != -1) {
+ uint16_t port = cli->port;
+ NTSTATUS status;
+ status = open_smb_socket(&cli->dest_ss, &port,
+ cli->timeout, &cli->fd);
+ if (NT_STATUS_IS_OK(status)) {
cli->port = port;
}
}
if (!my_name)
my_name = global_myname();
-
- if (!(cli = cli_initialise())) {
+
+ if (!(cli = cli_initialise_ex(signing_state))) {
return NT_STATUS_NO_MEMORY;
}
-
+
make_nmb_name(&calling, my_name, 0x0);
make_nmb_name(&called , dest_host, 0x20);
- if (cli_set_port(cli, port) != port) {
- cli_shutdown(cli);
- return NT_STATUS_UNSUCCESSFUL;
- }
-
+ cli_set_port(cli, port);
cli_set_timeout(cli, 10000); /* 10 seconds. */
if (dest_ss) {
ss = *dest_ss;
} else {
- zero_addr(&ss);
+ zero_sockaddr(&ss);
}
again:
*p = 0;
goto again;
}
- if (strcmp(called.name, star_smbserver_name)) {
- make_nmb_name(&called , star_smbserver_name, 0x20);
+ if (strcmp(called.name, STAR_SMBSERVER)) {
+ make_nmb_name(&called , STAR_SMBSERVER, 0x20);
goto again;
}
return NT_STATUS_BAD_NETWORK_NAME;
}
- cli_setup_signing_state(cli, signing_state);
-
if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
cli->use_spnego = False;
else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
cli->fallback_after_kerberos = true;
}
- if (!cli_negprot(cli)) {
- DEBUG(1,("failed negprot\n"));
- nt_status = cli_nt_error(cli);
- if (NT_STATUS_IS_OK(nt_status)) {
- nt_status = NT_STATUS_UNSUCCESSFUL;
- }
+ nt_status = cli_negprot(cli);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1, ("failed negprot: %s\n", nt_errstr(nt_status)));
cli_shutdown(cli);
return nt_status;
}
return nt_status;
}
+ cli->use_oplocks = ((flags & CLI_FULL_CONNECTION_OPLOCKS) != 0);
+ cli->use_level_II_oplocks =
+ ((flags & CLI_FULL_CONNECTION_LEVEL_II_OPLOCKS) != 0);
+
nt_status = cli_session_setup(cli, user, password, pw_len, password,
pw_len, domain);
if (!NT_STATUS_IS_OK(nt_status)) {
}
if (service) {
- if (!cli_send_tconX(cli, service, service_type, password, pw_len)) {
- nt_status = cli_nt_error(cli);
+ nt_status = cli_tcon_andx(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)) {
}
}
- cli_init_creds(cli, user, domain, password);
+ nt_status = cli_init_creds(cli, user, domain, password);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ cli_shutdown(cli);
+ return nt_status;
+ }
*output_cli = cli;
return NT_STATUS_OK;
*/
if(is_ipaddress(desthost)) {
- make_nmb_name(&called, star_smbserver_name, 0x20);
+ make_nmb_name(&called, STAR_SMBSERVER, 0x20);
} else {
make_nmb_name(&called, desthost, 0x20);
}
NTSTATUS status;
struct nmb_name smbservername;
- make_nmb_name(&smbservername, star_smbserver_name, 0x20);
+ make_nmb_name(&smbservername, STAR_SMBSERVER, 0x20);
/*
* If the name wasn't *SMBSERVER then