#include "includes.h"
#include "libsmb/libsmb.h"
-#include "popt_common.h"
+#include "auth_info.h"
#include "../libcli/auth/libcli_auth.h"
#include "../libcli/auth/spnego.h"
#include "smb_krb5.h"
-#include "../auth/ntlmssp/ntlmssp.h"
+#include "auth/credentials/credentials.h"
+#include "auth/gensec/gensec.h"
+#include "auth/ntlmssp/ntlmssp.h"
+#include "auth_generic.h"
#include "libads/kerberos_proto.h"
#include "krb5_env.h"
#include "../lib/util/tevent_ntstatus.h"
#include "async_smb.h"
#include "libsmb/nmblib.h"
#include "librpc/ndr/libndr.h"
-
-static const struct {
- int prot;
- 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"},
-};
+#include "../libcli/smb/smbXcli_base.h"
#define STAR_SMBSERVER "*SMBSERVER"
*******************************************************/
static NTSTATUS smb_bytes_talloc_string(TALLOC_CTX *mem_ctx,
- char *inbuf,
+ const uint8_t *hdr,
char **dest,
uint8_t *src,
size_t srclen,
ssize_t *destlen)
{
*destlen = clistr_pull_talloc(mem_ctx,
- inbuf,
- SVAL(inbuf, smb_flg2),
+ (const char *)hdr,
+ SVAL(hdr, HDR_FLG2),
dest,
(char *)src,
srclen,
return NT_STATUS_OK;
}
-/**
- * Set the user session key for a connection
- * @param cli The cli structure to add it too
- * @param session_key The session key used. (A copy of this is taken for the cli struct)
- *
- */
-
-static void cli_set_session_key (struct cli_state *cli, const DATA_BLOB session_key)
-{
- cli->user_session_key = data_blob(session_key.data, session_key.length);
-}
-
/****************************************************************************
Do an old lanman2 style session setup.
****************************************************************************/
uint16_t *vwv;
uint8_t *bytes;
char *tmp;
- uint16_t sec_mode = cli_state_security_mode(cli);
+ uint16_t sec_mode = smb1cli_conn_server_security_mode(cli->conn);
req = tevent_req_create(mem_ctx, &state,
struct cli_session_setup_lanman2_state);
return tevent_req_post(req, ev);
}
- if (!SMBencrypt(pass, cli_state_server_challenge(cli),
+ if (!SMBencrypt(pass, smb1cli_conn_server_challenge(cli->conn),
(uint8_t *)lm_response.data)) {
DEBUG(1, ("Password is > 14 chars in length, and is "
"therefore incompatible with Lanman "
* Plaintext mode needed, assume plaintext supplied.
*/
buf = talloc_array(talloc_tos(), uint8_t, 0);
- buf = smb_bytes_push_str(buf, cli_ucs2(cli), pass, passlen+1,
+ buf = smb_bytes_push_str(buf, smbXcli_conn_use_unicode(cli->conn), pass, passlen+1,
&converted_size);
if (tevent_req_nomem(buf, req)) {
return tevent_req_post(req, ev);
SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
SSVAL(vwv+3, 0, 2);
SSVAL(vwv+4, 0, 1);
- SIVAL(vwv+5, 0, cli_state_server_session_key(cli));
+ SIVAL(vwv+5, 0, smb1cli_conn_server_session_key(cli->conn));
SSVAL(vwv+7, 0, lm_response.length);
bytes = talloc_array(state, uint8_t, lm_response.length);
if (tevent_req_nomem(tmp, req)) {
return tevent_req_post(req, ev);
}
- bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1,
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), tmp, strlen(tmp)+1,
NULL);
TALLOC_FREE(tmp);
if (tevent_req_nomem(tmp, req)) {
return tevent_req_post(req, ev);
}
- bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1,
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), tmp, strlen(tmp)+1,
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);
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Unix", 5, NULL);
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Samba", 6, NULL);
if (tevent_req_nomem(bytes, req)) {
return tevent_req_post(req, ev);
struct cli_state *cli = state->cli;
uint32_t num_bytes;
uint8_t *in;
- char *inbuf;
+ uint8_t *inhdr;
uint8_t *bytes;
uint8_t *p;
NTSTATUS status;
return;
}
- inbuf = (char *)in;
+ inhdr = in + NBT_HDR_SIZE;
p = bytes;
- cli_state_set_uid(state->cli, SVAL(inbuf, smb_uid));
- cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
+ cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
status = smb_bytes_talloc_string(cli,
- inbuf,
+ inhdr,
&cli->server_os,
p,
bytes+num_bytes-p,
p += ret;
status = smb_bytes_talloc_string(cli,
- inbuf,
+ inhdr,
&cli->server_type,
p,
bytes+num_bytes-p,
p += ret;
status = smb_bytes_talloc_string(cli,
- inbuf,
+ inhdr,
&cli->server_domain,
p,
bytes+num_bytes-p,
}
p += ret;
- status = cli_set_username(cli, state->user);
- if (tevent_req_nterror(req, status)) {
- return;
- }
tevent_req_done(req);
}
return tevent_req_simple_recv_ntstatus(req);
}
-static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli, const char *user,
- const char *pass, size_t passlen,
- 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_lanman2_send(frame, ev, cli, user, pass, passlen,
- workgroup);
- if (req == NULL) {
- goto fail;
- }
- if (!tevent_req_poll_ntstatus(req, ev, &status)) {
- goto fail;
- }
- status = cli_session_setup_lanman2_recv(req);
- fail:
- TALLOC_FREE(frame);
- return status;
-}
-
/****************************************************************************
Work out suitable capabilities to offer the server.
****************************************************************************/
static uint32_t cli_session_setup_capabilities(struct cli_state *cli,
uint32_t sesssetup_capabilities)
{
- uint32_t client_capabilities = cli_state_capabilities(cli);
+ uint32_t client_capabilities = smb1cli_conn_capabilities(cli->conn);
/*
* We only send capabilities based on the mask for:
* - client only flags
* - flags used in both directions
*
- * We do not echo the server only flags.
+ * We do not echo the server only flags, except some legacy flags.
+ *
+ * SMB_CAP_LEGACY_CLIENT_MASK contains CAP_LARGE_READX and
+ * CAP_LARGE_WRITEX in order to allow us to do large reads
+ * against old Samba releases (<= 3.6.x).
*/
- client_capabilities &= (SMB_CAP_BOTH_MASK | SMB_CAP_CLIENT_MASK);
+ client_capabilities &= (SMB_CAP_BOTH_MASK | SMB_CAP_LEGACY_CLIENT_MASK);
/*
* Session Setup specific flags CAP_DYNAMIC_REAUTH
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 tevent_context *ev,
struct cli_state *cli,
struct tevent_req **psmbreq)
{
SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
SSVAL(vwv+3, 0, 2);
SSVAL(vwv+4, 0, cli_state_get_vc_num(cli));
- SIVAL(vwv+5, 0, cli_state_server_session_key(cli));
+ SIVAL(vwv+5, 0, smb1cli_conn_server_session_key(cli->conn));
SSVAL(vwv+7, 0, 0);
SSVAL(vwv+8, 0, 0);
SSVAL(vwv+9, 0, 0);
bytes = talloc_array(state, uint8_t, 0);
- bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, /* username */
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, /* username */
NULL);
- bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, /* workgroup */
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 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);
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Unix", 5, NULL);
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Samba", 6, NULL);
if (bytes == NULL) {
TALLOC_FREE(req);
}
struct tevent_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx,
- struct event_context *ev,
+ struct tevent_context *ev,
struct cli_state *cli)
{
struct tevent_req *req, *subreq;
return NULL;
}
- status = cli_smb_req_send(subreq);
- if (NT_STATUS_IS_OK(status)) {
+ status = smb1cli_req_chain_submit(&subreq, 1);
+ if (!NT_STATUS_IS_OK(status)) {
tevent_req_nterror(req, status);
return tevent_req_post(req, ev);
}
struct cli_state *cli = state->cli;
uint32_t num_bytes;
uint8_t *in;
- char *inbuf;
+ uint8_t *inhdr;
uint8_t *bytes;
uint8_t *p;
NTSTATUS status;
return;
}
- inbuf = (char *)in;
+ inhdr = in + NBT_HDR_SIZE;
p = bytes;
- cli_state_set_uid(state->cli, SVAL(inbuf, smb_uid));
- cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
+ cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
status = smb_bytes_talloc_string(cli,
- inbuf,
+ inhdr,
&cli->server_os,
p,
bytes+num_bytes-p,
p += ret;
status = smb_bytes_talloc_string(cli,
- inbuf,
+ inhdr,
&cli->server_type,
p,
bytes+num_bytes-p,
p += ret;
status = smb_bytes_talloc_string(cli,
- inbuf,
+ inhdr,
&cli->server_domain,
p,
bytes+num_bytes-p,
}
p += ret;
- status = cli_set_username(cli, "");
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
- }
tevent_req_done(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);
- return status;
-}
-
/****************************************************************************
Do a NT1 plaintext session setup.
****************************************************************************/
SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
SSVAL(vwv+3, 0, 2);
SSVAL(vwv+4, 0, cli_state_get_vc_num(cli));
- SIVAL(vwv+5, 0, cli_state_server_session_key(cli));
+ SIVAL(vwv+5, 0, smb1cli_conn_server_session_key(cli->conn));
SSVAL(vwv+7, 0, 0);
SSVAL(vwv+8, 0, 0);
SSVAL(vwv+9, 0, 0);
SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli, 0));
bytes = talloc_array(state, uint8_t, 0);
- bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), pass, strlen(pass)+1,
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), pass, strlen(pass)+1,
&passlen);
if (tevent_req_nomem(bytes, req)) {
return tevent_req_post(req, ev);
}
- SSVAL(vwv + (cli_ucs2(cli) ? 8 : 7), 0, passlen);
+ SSVAL(vwv + (smbXcli_conn_use_unicode(cli->conn) ? 8 : 7), 0, passlen);
- bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
user, strlen(user)+1, NULL);
- bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
workgroup, strlen(workgroup)+1, NULL);
- bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
"Unix", 5, NULL);
version = talloc_asprintf(talloc_tos(), "Samba %s",
if (tevent_req_nomem(version, req)){
return tevent_req_post(req, ev);
}
- bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
version, strlen(version)+1, NULL);
TALLOC_FREE(version);
struct cli_state *cli = state->cli;
uint32_t num_bytes;
uint8_t *in;
- char *inbuf;
+ uint8_t *inhdr;
uint8_t *bytes;
uint8_t *p;
NTSTATUS status;
return;
}
- inbuf = (char *)in;
+ inhdr = in + NBT_HDR_SIZE;
p = bytes;
- cli_state_set_uid(state->cli, SVAL(inbuf, smb_uid));
- cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
+ cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
status = smb_bytes_talloc_string(cli,
- inbuf,
+ inhdr,
&cli->server_os,
p,
bytes+num_bytes-p,
p += ret;
status = smb_bytes_talloc_string(cli,
- inbuf,
+ inhdr,
&cli->server_type,
p,
bytes+num_bytes-p,
p += ret;
status = smb_bytes_talloc_string(cli,
- inbuf,
+ inhdr,
&cli->server_domain,
p,
bytes+num_bytes-p,
}
p += ret;
- status = cli_set_username(cli, state->user);
- if (tevent_req_nterror(req, status)) {
- return;
- }
-
tevent_req_done(req);
}
return tevent_req_simple_recv_ntstatus(req);
}
-static NTSTATUS cli_session_setup_plain(struct cli_state *cli,
- const char *user, const char *pass,
- 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_plain_send(frame, ev, cli, user, pass,
- workgroup);
- if (req == NULL) {
- goto fail;
- }
- if (!tevent_req_poll_ntstatus(req, ev, &status)) {
- goto fail;
- }
- status = cli_session_setup_plain_recv(req);
- fail:
- TALLOC_FREE(frame);
- return status;
-}
-
/****************************************************************************
do a NT1 NTLM/LM encrypted session setup - for when extended security
is not negotiated.
DATA_BLOB names_blob;
server_chal =
- data_blob_const(cli_state_server_challenge(cli),
+ data_blob_const(smb1cli_conn_server_challenge(cli->conn),
8);
/*
return tevent_req_post(req, ev);
}
- SMBNTencrypt(pass, cli_state_server_challenge(cli),
+ SMBNTencrypt(pass, smb1cli_conn_server_challenge(cli->conn),
nt_response.data);
#endif
/* non encrypted password supplied. Ignore ntpass. */
}
if (!SMBencrypt(pass,
- cli_state_server_challenge(cli),
+ smb1cli_conn_server_challenge(cli->conn),
lm_response.data)) {
/*
* Oops, the LM response is
SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
SSVAL(vwv+3, 0, 2);
SSVAL(vwv+4, 0, cli_state_get_vc_num(cli));
- SIVAL(vwv+5, 0, cli_state_server_session_key(cli));
+ SIVAL(vwv+5, 0, smb1cli_conn_server_session_key(cli->conn));
SSVAL(vwv+7, 0, lm_response.length);
SSVAL(vwv+8, 0, nt_response.length);
SSVAL(vwv+9, 0, 0);
data_blob_free(&lm_response);
data_blob_free(&nt_response);
- bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
user, strlen(user)+1, NULL);
/*
if (tevent_req_nomem(workgroup_upper, req)) {
return tevent_req_post(req, ev);
}
- bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
workgroup_upper, strlen(workgroup_upper)+1,
NULL);
TALLOC_FREE(workgroup_upper);
- bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Unix", 5, NULL);
- bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Samba", 6, NULL);
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Unix", 5, NULL);
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Samba", 6, NULL);
if (tevent_req_nomem(bytes, req)) {
return tevent_req_post(req, ev);
}
struct cli_state *cli = state->cli;
uint32_t num_bytes;
uint8_t *in;
- char *inbuf;
+ uint8_t *inhdr;
uint8_t *bytes;
uint8_t *p;
NTSTATUS status;
return;
}
- inbuf = (char *)in;
+ inhdr = in + NBT_HDR_SIZE;
p = bytes;
- cli_state_set_uid(state->cli, SVAL(inbuf, smb_uid));
- cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
+ cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
status = smb_bytes_talloc_string(cli,
- inbuf,
+ inhdr,
&cli->server_os,
p,
bytes+num_bytes-p,
p += ret;
status = smb_bytes_talloc_string(cli,
- inbuf,
+ inhdr,
&cli->server_type,
p,
bytes+num_bytes-p,
p += ret;
status = smb_bytes_talloc_string(cli,
- inbuf,
+ inhdr,
&cli->server_domain,
p,
bytes+num_bytes-p,
}
p += ret;
- status = cli_set_username(cli, state->user);
- if (tevent_req_nterror(req, status)) {
- return;
- }
- if (cli_simple_set_signing(cli, state->session_key, state->response)
- && !cli_check_sign_mac(cli, (char *)in, 1)) {
+ if (smb1cli_conn_activate_signing(cli->conn, state->session_key, state->response)
+ && !smb1cli_conn_check_signing(cli->conn, (uint8_t *)in, 1)) {
tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
return;
}
if (state->session_key.data) {
- /* Have plaintext orginal */
- cli_set_session_key(cli, state->session_key);
+ struct smbXcli_session *session = state->cli->smb1.session;
+
+ status = smb1cli_session_set_session_key(session,
+ state->session_key);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
}
tevent_req_done(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);
- return status;
-}
-
/* The following is calculated from :
* (smb_size-4) = 35
* (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() )
uint16_t vwv[12];
uint8_t *buf;
+ DATA_BLOB smb2_blob;
+ struct iovec *recv_iov;
+
NTSTATUS status;
- char *inbuf;
+ uint8_t *inbuf;
DATA_BLOB ret_blob;
};
state->blob = blob;
state->cli = cli;
- usable_space = cli_state_available_size(cli,
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ usable_space = UINT16_MAX;
+ } else {
+ usable_space = cli_state_available_size(cli,
BASE_SESSSETUP_BLOB_PACKET_SIZE);
+ }
if (usable_space == 0) {
DEBUG(1, ("cli_session_setup_blob: cli->max_xmit too small "
struct tevent_req *subreq;
uint16_t thistime;
+ thistime = MIN(state->blob.length, state->max_blob_size);
+
+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+
+ state->smb2_blob.data = state->blob.data;
+ state->smb2_blob.length = thistime;
+
+ state->blob.data += thistime;
+ state->blob.length -= thistime;
+
+ subreq = smb2cli_session_setup_send(state, state->ev,
+ state->cli->conn,
+ state->cli->timeout,
+ state->cli->smb2.session,
+ 0, /* in_flags */
+ SMB2_CAP_DFS, /* in_capabilities */
+ 0, /* in_channel */
+ 0, /* in_previous_session_id */
+ &state->smb2_blob);
+ if (subreq == NULL) {
+ return false;
+ }
+ *psubreq = subreq;
+ return true;
+ }
+
SCVAL(state->vwv+0, 0, 0xFF);
SCVAL(state->vwv+0, 1, 0);
SSVAL(state->vwv+1, 0, 0);
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);
state->blob.data += thistime;
state->blob.length -= thistime;
- state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli),
+ state->buf = smb_bytes_push_str(state->buf, smbXcli_conn_use_unicode(state->cli->conn),
"Unix", 5, NULL);
- state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli),
+ state->buf = smb_bytes_push_str(state->buf, smbXcli_conn_use_unicode(state->cli->conn),
"Samba", 6, NULL);
if (state->buf == NULL) {
return false;
NTSTATUS status;
uint8_t *p;
uint16_t blob_length;
- uint8_t *inbuf;
+ uint8_t *in;
+ uint8_t *inhdr;
ssize_t ret;
- status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv,
- &num_bytes, &bytes);
+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+ status = smb2cli_session_setup_recv(subreq, state,
+ &state->recv_iov,
+ &state->ret_blob);
+ } else {
+ status = cli_smb_recv(subreq, state, &in, 4, &wct, &vwv,
+ &num_bytes, &bytes);
+ TALLOC_FREE(state->buf);
+ }
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)
&& !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
}
state->status = status;
- TALLOC_FREE(state->buf);
- state->inbuf = (char *)inbuf;
- cli_state_set_uid(state->cli, SVAL(inbuf, smb_uid));
- cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+ goto next;
+ }
+
+ state->inbuf = in;
+ inhdr = in + NBT_HDR_SIZE;
+ cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
blob_length = SVAL(vwv+3, 0);
if (blob_length > num_bytes) {
p = bytes + blob_length;
status = smb_bytes_talloc_string(cli,
- (char *)inbuf,
+ inhdr,
&cli->server_os,
p,
bytes+num_bytes-p,
p += ret;
status = smb_bytes_talloc_string(cli,
- (char *)inbuf,
+ inhdr,
&cli->server_type,
p,
bytes+num_bytes-p,
p += ret;
status = smb_bytes_talloc_string(cli,
- (char *)inbuf,
+ inhdr,
&cli->server_domain,
p,
bytes+num_bytes-p,
}
p += ret;
+next:
if (state->blob.length != 0) {
/*
* More to send
static NTSTATUS cli_sesssetup_blob_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
DATA_BLOB *pblob,
- char **pinbuf)
+ uint8_t **pinbuf,
+ struct iovec **precv_iov)
{
struct cli_sesssetup_blob_state *state = tevent_req_data(
req, struct cli_sesssetup_blob_state);
NTSTATUS status;
- char *inbuf;
+ uint8_t *inbuf;
+ struct iovec *recv_iov;
if (tevent_req_is_nterror(req, &status)) {
+ TALLOC_FREE(state->cli->smb2.session);
cli_state_set_uid(state->cli, UID_FIELD_INVALID);
return status;
}
inbuf = talloc_move(mem_ctx, &state->inbuf);
+ recv_iov = talloc_move(mem_ctx, &state->recv_iov);
if (pblob != NULL) {
*pblob = state->ret_blob;
}
if (pinbuf != NULL) {
*pinbuf = inbuf;
}
+ if (precv_iov != NULL) {
+ *precv_iov = recv_iov;
+ }
/* could be NT_STATUS_MORE_PROCESSING_REQUIRED */
return state->status;
}
setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
}
+#endif /* HAVE_KRB5 */
+
/****************************************************************************
- Do a spnego/kerberos encrypted session setup.
+ Do a spnego/NTLMSSP encrypted session setup.
****************************************************************************/
-struct cli_session_setup_kerberos_state {
+struct cli_session_setup_gensec_state {
+ struct tevent_context *ev;
struct cli_state *cli;
- DATA_BLOB negTokenTarg;
- DATA_BLOB session_key_krb5;
- ADS_STATUS ads_status;
+ struct auth_generic_state *auth_generic;
+ bool is_anonymous;
+ DATA_BLOB blob_in;
+ uint8_t *inbuf;
+ struct iovec *recv_iov;
+ DATA_BLOB blob_out;
+ bool local_ready;
+ bool remote_ready;
+ DATA_BLOB session_key;
};
-static void cli_session_setup_kerberos_done(struct tevent_req *subreq);
+static int cli_session_setup_gensec_state_destructor(
+ struct cli_session_setup_gensec_state *state)
+{
+ TALLOC_FREE(state->auth_generic);
+ data_blob_clear_free(&state->session_key);
+ return 0;
+}
+
+static void cli_session_setup_gensec_local_next(struct tevent_req *req);
+static void cli_session_setup_gensec_local_done(struct tevent_req *subreq);
+static void cli_session_setup_gensec_remote_next(struct tevent_req *req);
+static void cli_session_setup_gensec_remote_done(struct tevent_req *subreq);
+static void cli_session_setup_gensec_ready(struct tevent_req *req);
-static struct tevent_req *cli_session_setup_kerberos_send(
+static struct tevent_req *cli_session_setup_gensec_send(
TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
- const char *principal)
+ const char *user, const char *pass, const char *domain,
+ enum credentials_use_kerberos krb5_state,
+ const char *target_service,
+ const char *target_hostname,
+ const char *target_principal)
{
- struct tevent_req *req, *subreq;
- struct cli_session_setup_kerberos_state *state;
- int rc;
-
- DEBUG(2,("Doing kerberos session setup\n"));
+ struct tevent_req *req;
+ struct cli_session_setup_gensec_state *state;
+ NTSTATUS status;
+ bool use_spnego_principal = lp_client_use_spnego_principal();
req = tevent_req_create(mem_ctx, &state,
- struct cli_session_setup_kerberos_state);
+ struct cli_session_setup_gensec_state);
if (req == NULL) {
return NULL;
}
+ state->ev = ev;
state->cli = cli;
- state->ads_status = ADS_SUCCESS;
- /*
- * Ok, this is cheating: spnego_gen_krb5_negTokenInit can block if
- * we have to acquire a ticket. To be fixed later :-)
- */
- rc = spnego_gen_krb5_negTokenInit(state, principal, 0, &state->negTokenTarg,
- &state->session_key_krb5, 0, NULL);
- if (rc) {
- DEBUG(1, ("cli_session_setup_kerberos: "
- "spnego_gen_krb5_negTokenInit failed: %s\n",
- error_message(rc)));
- state->ads_status = ADS_ERROR_KRB5(rc);
- tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+ talloc_set_destructor(
+ state, cli_session_setup_gensec_state_destructor);
+
+ status = auth_generic_client_prepare(state, &state->auth_generic);
+ if (tevent_req_nterror(req, status)) {
return tevent_req_post(req, ev);
}
-#if 0
- file_save("negTokenTarg.dat", state->negTokenTarg.data,
- state->negTokenTarg.length);
-#endif
+ gensec_want_feature(state->auth_generic->gensec_security,
+ GENSEC_FEATURE_SESSION_KEY);
+ if (cli->use_ccache) {
+ gensec_want_feature(state->auth_generic->gensec_security,
+ GENSEC_FEATURE_NTLM_CCACHE);
+ if (pass != NULL && strlen(pass) == 0) {
+ /*
+ * some callers pass "" as no password
+ *
+ * GENSEC_FEATURE_NTLM_CCACHE only handles
+ * NULL as no password.
+ */
+ pass = NULL;
+ }
+ }
- subreq = cli_sesssetup_blob_send(state, ev, cli, state->negTokenTarg);
- if (tevent_req_nomem(subreq, req)) {
+ status = auth_generic_set_username(state->auth_generic, user);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ status = auth_generic_set_domain(state->auth_generic, domain);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (cli->pw_nt_hash) {
+ struct samr_Password nt_hash;
+ size_t converted;
+ bool ok;
+
+ if (pass == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ converted = strhex_to_str((char *)nt_hash.hash,
+ sizeof(nt_hash.hash),
+ pass, strlen(pass));
+ if (converted != sizeof(nt_hash.hash)) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ ok = cli_credentials_set_nt_hash(state->auth_generic->credentials,
+ &nt_hash, CRED_SPECIFIED);
+ if (!ok) {
+ tevent_req_oom(req);
+ return tevent_req_post(req, ev);
+ }
+ } else {
+ status = auth_generic_set_password(state->auth_generic, pass);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ cli_credentials_set_kerberos_state(state->auth_generic->credentials,
+ krb5_state);
+
+ if (krb5_state == CRED_DONT_USE_KERBEROS) {
+ use_spnego_principal = false;
+ }
+
+ if (target_service != NULL) {
+ status = gensec_set_target_service(
+ state->auth_generic->gensec_security,
+ target_service);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ if (target_hostname != NULL) {
+ status = gensec_set_target_hostname(
+ state->auth_generic->gensec_security,
+ target_hostname);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ if (target_principal != NULL) {
+ status = gensec_set_target_principal(
+ state->auth_generic->gensec_security,
+ target_principal);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ use_spnego_principal = false;
+ } else if (target_service != NULL && target_hostname != NULL) {
+ use_spnego_principal = false;
+ }
+
+ if (use_spnego_principal) {
+ const DATA_BLOB *b;
+ b = smbXcli_conn_server_gss_blob(cli->conn);
+ if (b != NULL) {
+ state->blob_in = *b;
+ }
+ }
+
+ state->is_anonymous = cli_credentials_is_anonymous(state->auth_generic->credentials);
+
+ status = auth_generic_client_start(state->auth_generic,
+ GENSEC_OID_SPNEGO);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ state->cli->smb2.session = smbXcli_session_create(cli,
+ cli->conn);
+ if (tevent_req_nomem(state->cli->smb2.session, req)) {
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ cli_session_setup_gensec_local_next(req);
+ if (!tevent_req_is_in_progress(req)) {
return tevent_req_post(req, ev);
}
- tevent_req_set_callback(subreq, cli_session_setup_kerberos_done, req);
+
return req;
}
-static void cli_session_setup_kerberos_done(struct tevent_req *subreq)
+static void cli_session_setup_gensec_local_next(struct tevent_req *req)
{
- 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;
+ struct cli_session_setup_gensec_state *state =
+ tevent_req_data(req,
+ struct cli_session_setup_gensec_state);
+ struct tevent_req *subreq = NULL;
+
+ if (state->local_ready) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ subreq = gensec_update_send(state, state->ev,
+ state->auth_generic->gensec_security,
+ state->blob_in);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, cli_session_setup_gensec_local_done, req);
+}
+
+static void cli_session_setup_gensec_local_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct cli_session_setup_gensec_state *state =
+ tevent_req_data(req,
+ struct cli_session_setup_gensec_state);
NTSTATUS status;
- status = cli_sesssetup_blob_recv(subreq, talloc_tos(), NULL, &inbuf);
+ status = gensec_update_recv(subreq, state, &state->blob_out);
TALLOC_FREE(subreq);
- if (!NT_STATUS_IS_OK(status)) {
+ state->blob_in = data_blob_null;
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED))
+ {
tevent_req_nterror(req, status);
return;
}
- cli_set_session_key(state->cli, state->session_key_krb5);
+ if (NT_STATUS_IS_OK(status)) {
+ state->local_ready = true;
+ }
- if (cli_simple_set_signing(state->cli, state->session_key_krb5,
- data_blob_null)
- && !cli_check_sign_mac(state->cli, inbuf, 1)) {
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ if (state->local_ready && state->remote_ready) {
+ cli_session_setup_gensec_ready(req);
return;
}
- tevent_req_done(req);
+ cli_session_setup_gensec_remote_next(req);
}
-static ADS_STATUS cli_session_setup_kerberos_recv(struct tevent_req *req)
+static void cli_session_setup_gensec_remote_next(struct tevent_req *req)
{
- struct cli_session_setup_kerberos_state *state = tevent_req_data(
- req, struct cli_session_setup_kerberos_state);
- NTSTATUS status;
+ struct cli_session_setup_gensec_state *state =
+ tevent_req_data(req,
+ struct cli_session_setup_gensec_state);
+ struct tevent_req *subreq = NULL;
- if (tevent_req_is_nterror(req, &status)) {
- return ADS_ERROR_NT(status);
+ if (state->remote_ready) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
}
- return state->ads_status;
-}
-
-static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli,
- const char *principal)
-{
- 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);
- 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.
-****************************************************************************/
-struct cli_session_setup_ntlmssp_state {
- struct tevent_context *ev;
- struct cli_state *cli;
- struct ntlmssp_state *ntlmssp_state;
- int turn;
- DATA_BLOB blob_out;
-};
-
-static int cli_session_setup_ntlmssp_state_destructor(
- struct cli_session_setup_ntlmssp_state *state)
-{
- if (state->ntlmssp_state != NULL) {
- TALLOC_FREE(state->ntlmssp_state);
+ subreq = cli_sesssetup_blob_send(state, state->ev,
+ state->cli, state->blob_out);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
}
- return 0;
+ tevent_req_set_callback(subreq,
+ cli_session_setup_gensec_remote_done,
+ req);
}
-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)
+static void cli_session_setup_gensec_remote_done(struct tevent_req *subreq)
{
- struct tevent_req *req, *subreq;
- struct cli_session_setup_ntlmssp_state *state;
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct cli_session_setup_gensec_state *state =
+ tevent_req_data(req,
+ struct cli_session_setup_gensec_state);
NTSTATUS status;
- DATA_BLOB blob_out;
- const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
-
- req = tevent_req_create(mem_ctx, &state,
- struct cli_session_setup_ntlmssp_state);
- if (req == NULL) {
- return NULL;
- }
- state->ev = ev;
- state->cli = cli;
- state->turn = 1;
- state->ntlmssp_state = NULL;
- talloc_set_destructor(
- state, cli_session_setup_ntlmssp_state_destructor);
+ TALLOC_FREE(state->inbuf);
+ TALLOC_FREE(state->recv_iov);
- status = ntlmssp_client_start(state,
- lp_netbios_name(),
- lp_workgroup(),
- lp_client_ntlmv2_auth(),
- &state->ntlmssp_state);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
- ntlmssp_want_feature(state->ntlmssp_state,
- NTLMSSP_FEATURE_SESSION_KEY);
- if (cli->use_ccache) {
- ntlmssp_want_feature(state->ntlmssp_state,
- NTLMSSP_FEATURE_CCACHE);
- }
- status = ntlmssp_set_username(state->ntlmssp_state, user);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
- 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;
+ status = cli_sesssetup_blob_recv(subreq, state, &state->blob_in,
+ &state->inbuf, &state->recv_iov);
+ TALLOC_FREE(subreq);
+ data_blob_free(&state->blob_out);
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED))
+ {
+ tevent_req_nterror(req, status);
+ return;
}
- state->blob_out = spnego_gen_negTokenInit(state, OIDs_ntlm, &blob_out, NULL);
- data_blob_free(&blob_out);
+ if (NT_STATUS_IS_OK(status)) {
+ state->remote_ready = true;
+ }
- subreq = cli_sesssetup_blob_send(state, ev, cli, state->blob_out);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
+ if (state->local_ready && state->remote_ready) {
+ cli_session_setup_gensec_ready(req);
+ return;
}
- 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);
+
+ cli_session_setup_gensec_local_next(req);
}
-static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq)
+static void cli_session_setup_gensec_ready(struct tevent_req *req)
{
- 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;
+ struct cli_session_setup_gensec_state *state =
+ tevent_req_data(req,
+ struct cli_session_setup_gensec_state);
+ const char *server_domain = NULL;
NTSTATUS status;
- status = cli_sesssetup_blob_recv(subreq, talloc_tos(), &blob_in,
- &inbuf);
- TALLOC_FREE(subreq);
- data_blob_free(&state->blob_out);
+ if (state->blob_in.length != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
- if (NT_STATUS_IS_OK(status)) {
- if (state->cli->server_domain[0] == '\0') {
- TALLOC_FREE(state->cli->server_domain);
- state->cli->server_domain = talloc_strdup(state->cli,
- state->ntlmssp_state->server.netbios_domain);
- if (state->cli->server_domain == NULL) {
- tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
- return;
- }
- }
- cli_set_session_key(
- state->cli, state->ntlmssp_state->session_key);
+ if (state->blob_out.length != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
- if (cli_simple_set_signing(
- state->cli, state->ntlmssp_state->session_key,
- data_blob_null)
- && !cli_check_sign_mac(state->cli, inbuf, 1)) {
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ /*
+ * gensec_ntlmssp_server_domain() returns NULL
+ * if NTLMSSP is not used.
+ *
+ * We can remove this later
+ * and leave the server domain empty for SMB2 and above
+ * in future releases.
+ */
+ server_domain = gensec_ntlmssp_server_domain(
+ state->auth_generic->gensec_security);
+
+ if (state->cli->server_domain[0] == '\0' && server_domain != NULL) {
+ TALLOC_FREE(state->cli->server_domain);
+ state->cli->server_domain = talloc_strdup(state->cli,
+ server_domain);
+ if (state->cli->server_domain == NULL) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
- TALLOC_FREE(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 (blob_in.length == 0) {
- tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+ status = gensec_session_key(state->auth_generic->gensec_security,
+ state, &state->session_key);
+ if (tevent_req_nterror(req, status)) {
return;
}
- 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(state, blob_in, &msg_in,
- &tmp_blob);
- data_blob_free(&tmp_blob);
- } else {
- parse_ret = spnego_parse_auth_response(state, 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);
+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+ struct smbXcli_session *session = state->cli->smb2.session;
+
+ if (state->is_anonymous) {
+ /*
+ * Windows server does not set the
+ * SMB2_SESSION_FLAG_IS_GUEST nor
+ * SMB2_SESSION_FLAG_IS_NULL flag.
+ *
+ * This fix makes sure we do not try
+ * to verify a signature on the final
+ * session setup response.
+ */
+ tevent_req_done(req);
return;
}
- }
- status = ntlmssp_update(state->ntlmssp_state, msg_in, &blob_out);
+ status = smb2cli_session_set_session_key(session,
+ state->session_key,
+ state->recv_iov);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ } else {
+ struct smbXcli_session *session = state->cli->smb1.session;
+ bool active;
- if (!NT_STATUS_IS_OK(status)
- && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- TALLOC_FREE(state->ntlmssp_state);
- tevent_req_nterror(req, status);
- return;
- }
+ status = smb1cli_session_set_session_key(session,
+ state->session_key);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
- state->blob_out = spnego_gen_auth(state, blob_out);
- if (tevent_req_nomem(state->blob_out.data, req)) {
- return;
- }
+ active = smb1cli_conn_activate_signing(state->cli->conn,
+ state->session_key,
+ data_blob_null);
+ if (active) {
+ bool ok;
- subreq = cli_sesssetup_blob_send(state, state->ev, state->cli,
- state->blob_out);
- if (tevent_req_nomem(subreq, req)) {
- return;
+ ok = smb1cli_conn_check_signing(state->cli->conn,
+ state->inbuf, 1);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+ }
}
- tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
+
+ tevent_req_done(req);
}
-static NTSTATUS cli_session_setup_ntlmssp_recv(struct tevent_req *req)
+static NTSTATUS cli_session_setup_gensec_recv(struct tevent_req *req)
{
- struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
- req, struct cli_session_setup_ntlmssp_state);
+ struct cli_session_setup_gensec_state *state =
+ tevent_req_data(req,
+ struct cli_session_setup_gensec_state);
NTSTATUS status;
if (tevent_req_is_nterror(req, &status)) {
return NT_STATUS_OK;
}
-static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli,
- const char *user,
- const char *pass,
- const char *domain)
+#ifdef HAVE_KRB5
+
+static char *cli_session_setup_get_principal(
+ TALLOC_CTX *mem_ctx, const char *spnego_principal,
+ const char *remote_name, const char *dest_realm)
{
- struct tevent_context *ev;
- struct tevent_req *req;
- NTSTATUS status = NT_STATUS_NO_MEMORY;
+ char *principal = NULL;
- if (cli_has_async_calls(cli)) {
- return NT_STATUS_INVALID_PARAMETER;
+ if (!lp_client_use_spnego_principal() ||
+ strequal(spnego_principal, ADS_IGNORE_PRINCIPAL)) {
+ spnego_principal = NULL;
}
- ev = tevent_context_init(talloc_tos());
- if (ev == NULL) {
- goto fail;
+ if (spnego_principal != NULL) {
+ DEBUG(3, ("cli_session_setup_spnego: using spnego provided "
+ "principal %s\n", spnego_principal));
+ return talloc_strdup(mem_ctx, spnego_principal);
}
- req = cli_session_setup_ntlmssp_send(ev, ev, cli, user, pass, domain);
- if (req == NULL) {
- goto fail;
+ if (is_ipaddress(remote_name) ||
+ strequal(remote_name, STAR_SMBSERVER)) {
+ return NULL;
}
- if (!tevent_req_poll_ntstatus(req, ev, &status)) {
- goto fail;
+
+ DEBUG(3, ("cli_session_setup_spnego: using target "
+ "hostname not SPNEGO principal\n"));
+
+ if (dest_realm) {
+ char *realm = strupper_talloc(talloc_tos(), dest_realm);
+ if (realm == NULL) {
+ return NULL;
+ }
+ principal = talloc_asprintf(talloc_tos(), "cifs/%s@%s",
+ remote_name, realm);
+ TALLOC_FREE(realm);
+ } else {
+ principal = kerberos_get_principal_from_service_hostname(
+ talloc_tos(), "cifs", remote_name, lp_realm());
}
- status = cli_session_setup_ntlmssp_recv(req);
-fail:
- TALLOC_FREE(ev);
- return status;
+ DEBUG(3, ("cli_session_setup_spnego: guessed server principal=%s\n",
+ principal ? principal : "<null>"));
+
+ return principal;
+}
+#endif
+
+static char *cli_session_setup_get_account(TALLOC_CTX *mem_ctx,
+ const char *principal)
+{
+ char *account, *p;
+
+ account = talloc_strdup(mem_ctx, principal);
+ if (account == NULL) {
+ return NULL;
+ }
+ p = strchr_m(account, '@');
+ if (p != NULL) {
+ *p = '\0';
+ }
+ return account;
}
/****************************************************************************
dest_realm: The realm we're connecting to, if NULL we use our default realm.
****************************************************************************/
-static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli,
- const char *user,
- const char *pass,
- const char *user_domain,
- const char * dest_realm)
+struct cli_session_setup_spnego_state {
+ struct tevent_context *ev;
+ struct cli_state *cli;
+ const char *target_hostname;
+ const char *user;
+ const char *account;
+ const char *pass;
+ const char *user_domain;
+ const char *dest_realm;
+ ADS_STATUS result;
+};
+
+#ifdef HAVE_KRB5
+static void cli_session_setup_spnego_done_krb(struct tevent_req *subreq);
+#endif
+
+static void cli_session_setup_spnego_done_ntlmssp(struct tevent_req *subreq);
+
+static struct tevent_req *cli_session_setup_spnego_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
+ const char *user, const char *pass, const char *user_domain)
{
+ struct tevent_req *req, *subreq;
+ struct cli_session_setup_spnego_state *state;
char *principal = NULL;
char *OIDs[ASN1_MAX_OIDS];
int i;
+ const char *dest_realm = cli_state_remote_realm(cli);
const DATA_BLOB *server_blob;
- DATA_BLOB blob = data_blob_null;
- const char *p = NULL;
- char *account = NULL;
- NTSTATUS status;
- server_blob = cli_state_server_gss_blob(cli);
- if (server_blob) {
- blob = data_blob(server_blob->data, server_blob->length);
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_session_setup_spnego_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->cli = cli;
+ state->user = user;
+ state->pass = pass;
+ state->user_domain = user_domain;
+ state->dest_realm = dest_realm;
+
+ state->account = cli_session_setup_get_account(state, user);
+ if (tevent_req_nomem(state->account, req)) {
+ return tevent_req_post(req, ev);
}
- DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)blob.length));
+ state->target_hostname = smbXcli_conn_remote_name(cli->conn);
+ server_blob = smbXcli_conn_server_gss_blob(cli->conn);
+
+ DEBUG(3,("Doing spnego session setup (blob length=%lu)\n",
+ (unsigned long)server_blob->length));
/* the server might not even do spnego */
- if (blob.length == 0) {
+ if (server_blob->length == 0) {
DEBUG(3,("server didn't supply a full spnego negprot\n"));
goto ntlmssp;
}
* negprot reply. It is WRONG to depend on the principal sent in the
* negprot reply, but right now we do it. If we don't receive one,
* we try to best guess, then fall back to NTLM. */
- if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &principal, NULL) ||
+ if (!spnego_parse_negTokenInit(state, *server_blob, OIDs,
+ &principal, NULL) ||
OIDs[0] == NULL) {
- data_blob_free(&blob);
- return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ state->result = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
}
- data_blob_free(&blob);
/* make sure the server understands kerberos */
for (i=0;OIDs[i];i++) {
DEBUG(3,("got principal=%s\n", principal ? principal : "<null>"));
- status = cli_set_username(cli, user);
- if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(principal);
- return ADS_ERROR_NT(status);
- }
-
#ifdef HAVE_KRB5
/* If password is set we reauthenticate to kerberos server
* and do not store results */
- if (cli->got_kerberos_mechanism && cli->use_kerberos) {
- ADS_STATUS rc;
- const char *remote_name = cli_state_remote_name(cli);
+ if (user && *user && cli->got_kerberos_mechanism && cli->use_kerberos) {
+ char *tmp;
+
+ tmp = cli_session_setup_get_principal(
+ talloc_tos(), principal, state->target_hostname, dest_realm);
+ TALLOC_FREE(principal);
+ principal = tmp;
if (pass && *pass) {
int ret;
ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL);
if (ret){
+ DEBUG(0, ("Kinit for %s to access %s failed: %s\n", user, principal, error_message(ret)));
TALLOC_FREE(principal);
- DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
if (cli->fallback_after_kerberos)
goto ntlmssp;
- return ADS_ERROR_KRB5(ret);
+ state->result = ADS_ERROR_KRB5(ret);
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
}
}
- /* We may not be allowed to use the server-supplied SPNEGO principal, or it may not have been supplied to us
- */
- if (!lp_client_use_spnego_principal() || strequal(principal, ADS_IGNORE_PRINCIPAL)) {
- TALLOC_FREE(principal);
+ if (principal) {
+ subreq = cli_session_setup_gensec_send(
+ state, ev, cli,
+ state->account, pass, user_domain,
+ CRED_MUST_USE_KERBEROS,
+ "cifs", state->target_hostname, principal);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(
+ subreq, cli_session_setup_spnego_done_krb,
+ req);
+ return req;
}
+ }
+#endif
- if (principal == NULL &&
- !is_ipaddress(remote_name) &&
- !strequal(STAR_SMBSERVER,
- remote_name)) {
- char *realm = NULL;
- char *host = NULL;
- DEBUG(3,("cli_session_setup_spnego: using target "
- "hostname not SPNEGO principal\n"));
-
- host = strchr_m(remote_name, '.');
- if (dest_realm) {
- realm = SMB_STRDUP(dest_realm);
- if (!realm) {
- return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
- }
- strupper_m(realm);
- } else {
- if (host) {
- /* DNS name. */
- realm = kerberos_get_realm_from_hostname(remote_name);
- } else {
- /* NetBIOS name - use our realm. */
- realm = kerberos_get_default_realm_from_ccache();
- }
- }
+ntlmssp:
+ subreq = cli_session_setup_gensec_send(
+ state, state->ev, state->cli,
+ state->account, state->pass, state->user_domain,
+ CRED_DONT_USE_KERBEROS,
+ "cifs", state->target_hostname, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(
+ subreq, cli_session_setup_spnego_done_ntlmssp, req);
+ return req;
+}
- if (realm == NULL || *realm == '\0') {
- realm = SMB_STRDUP(lp_realm());
- if (!realm) {
- return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
- }
- strupper_m(realm);
- DEBUG(3,("cli_session_setup_spnego: cannot "
- "get realm from dest_realm %s, "
- "desthost %s. Using default "
- "smb.conf realm %s\n",
- dest_realm ? dest_realm : "<null>",
- remote_name,
- realm));
- }
+#ifdef HAVE_KRB5
+static void cli_session_setup_spnego_done_krb(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_session_setup_spnego_state *state = tevent_req_data(
+ req, struct cli_session_setup_spnego_state);
+ NTSTATUS status;
- principal = talloc_asprintf(talloc_tos(),
- "cifs/%s@%s",
- remote_name,
- realm);
- if (!principal) {
- SAFE_FREE(realm);
- return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
- }
- DEBUG(3,("cli_session_setup_spnego: guessed "
- "server principal=%s\n",
- principal ? principal : "<null>"));
+ status = cli_session_setup_gensec_recv(subreq);
+ TALLOC_FREE(subreq);
+ state->result = ADS_ERROR_NT(status);
- SAFE_FREE(realm);
- }
+ if (ADS_ERR_OK(state->result) ||
+ !state->cli->fallback_after_kerberos) {
+ tevent_req_done(req);
+ return;
+ }
- if (principal) {
- rc = cli_session_setup_kerberos(cli, principal);
- if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) {
- TALLOC_FREE(principal);
- return rc;
- }
- }
+ subreq = cli_session_setup_gensec_send(
+ state, state->ev, state->cli,
+ state->account, state->pass, state->user_domain,
+ CRED_DONT_USE_KERBEROS,
+ "cifs", state->target_hostname, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
}
+ tevent_req_set_callback(subreq, cli_session_setup_spnego_done_ntlmssp,
+ req);
+}
#endif
- TALLOC_FREE(principal);
+static void cli_session_setup_spnego_done_ntlmssp(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_session_setup_spnego_state *state = tevent_req_data(
+ req, struct cli_session_setup_spnego_state);
+ NTSTATUS status;
-ntlmssp:
+ status = cli_session_setup_gensec_recv(subreq);
+ TALLOC_FREE(subreq);
+ state->result = ADS_ERROR_NT(status);
+ tevent_req_done(req);
+}
- account = talloc_strdup(talloc_tos(), user);
- if (!account) {
- return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
- }
+static ADS_STATUS cli_session_setup_spnego_recv(struct tevent_req *req)
+{
+ struct cli_session_setup_spnego_state *state = tevent_req_data(
+ req, struct cli_session_setup_spnego_state);
- /* when falling back to ntlmssp while authenticating with a machine
- * account strip off the realm - gd */
+ return state->result;
+}
- if ((p = strchr_m(user, '@')) != NULL) {
- account[PTR_DIFF(p,user)] = '\0';
- }
+struct cli_session_setup_state {
+ uint8_t dummy;
+};
- return ADS_ERROR_NT(cli_session_setup_ntlmssp(cli, account, pass, user_domain));
-}
+static void cli_session_setup_done_lanman2(struct tevent_req *subreq);
+static void cli_session_setup_done_spnego(struct tevent_req *subreq);
+static void cli_session_setup_done_guest(struct tevent_req *subreq);
+static void cli_session_setup_done_plain(struct tevent_req *subreq);
+static void cli_session_setup_done_nt1(struct tevent_req *subreq);
/****************************************************************************
Send a session setup. The username and workgroup is in UNIX character
password is in plaintext, the same should be done.
****************************************************************************/
-NTSTATUS cli_session_setup(struct cli_state *cli,
- const char *user,
- const char *pass, int passlen,
- const char *ntpass, int ntpasslen,
- const char *workgroup)
+struct tevent_req *cli_session_setup_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *user,
+ const char *pass, int passlen,
+ const char *ntpass, int ntpasslen,
+ const char *workgroup)
{
+ struct tevent_req *req, *subreq;
+ struct cli_session_setup_state *state;
char *p;
char *user2;
- uint16_t sec_mode = cli_state_security_mode(cli);
+ uint16_t sec_mode = smb1cli_conn_server_security_mode(cli->conn);
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_session_setup_state);
+ if (req == NULL) {
+ return NULL;
+ }
if (user) {
- user2 = talloc_strdup(talloc_tos(), user);
+ user2 = talloc_strdup(state, user);
} else {
- user2 = talloc_strdup(talloc_tos(), "");
+ user2 = talloc_strdup(state, "");
}
if (user2 == NULL) {
- return NT_STATUS_NO_MEMORY;
+ tevent_req_oom(req);
+ return tevent_req_post(req, ev);
}
if (!workgroup) {
(p=strchr_m(user2,*lp_winbind_separator()))) {
*p = 0;
user = p+1;
- strupper_m(user2);
+ if (!strupper_m(user2)) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
workgroup = user2;
}
- if (cli_state_protocol(cli) < PROTOCOL_LANMAN1) {
- return NT_STATUS_OK;
+ if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_LANMAN1) {
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
}
/* now work out what sort of session setup we are going to
/* if its an older server then we have to use the older request format */
- if (cli_state_protocol(cli) < PROTOCOL_NT1) {
+ if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_NT1) {
if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
DEBUG(1, ("Server requested LM password but 'client lanman auth = no'"
" or 'client ntlmv2 auth = yes'\n"));
- return NT_STATUS_ACCESS_DENIED;
- }
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return tevent_req_post(req, ev);
+ }
if ((sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
!lp_client_plaintext_auth() && (*pass)) {
- DEBUG(1, ("Server requested LM password but 'client plaintext auth = no'"
+ DEBUG(1, ("Server requested PLAINTEXT password but 'client plaintext auth = no'"
" or 'client ntlmv2 auth = yes'\n"));
- return NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return tevent_req_post(req, ev);
}
- return cli_session_setup_lanman2(cli, user, pass, passlen,
- workgroup);
+ subreq = cli_session_setup_lanman2_send(
+ state, ev, cli, user, pass, passlen, workgroup);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_session_setup_done_lanman2,
+ req);
+ return req;
+ }
+
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ subreq = cli_session_setup_spnego_send(
+ state, ev, cli, user, pass, workgroup);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_session_setup_done_spnego,
+ req);
+ return req;
}
/* if no user is supplied then we have to do an anonymous connection.
passwords are ignored */
- if (!user || !*user)
- return cli_session_setup_guest(cli);
+ if (!user || !*user) {
+ subreq = cli_session_setup_guest_send(state, ev, cli);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_session_setup_done_guest,
+ req);
+ return req;
+ }
/* if the server is share level then send a plaintext null
password at this point. The password is sent in the tree
connect */
- if ((sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0)
- return cli_session_setup_plain(cli, user, "", workgroup);
+ if ((sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0) {
+ subreq = cli_session_setup_plain_send(
+ state, ev, cli, user, "", workgroup);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_session_setup_done_plain,
+ req);
+ return req;
+ }
/* if the server doesn't support encryption then we have to use
plaintext. The second password is ignored */
if ((sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
if (!lp_client_plaintext_auth() && (*pass)) {
- DEBUG(1, ("Server requested LM password but 'client plaintext auth = no'"
+ DEBUG(1, ("Server requested PLAINTEXT password but 'client plaintext auth = no'"
" or 'client ntlmv2 auth = yes'\n"));
- return NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return tevent_req_post(req, ev);
}
- return cli_session_setup_plain(cli, user, pass, workgroup);
+ subreq = cli_session_setup_plain_send(
+ state, ev, cli, user, pass, workgroup);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_session_setup_done_plain,
+ req);
+ return req;
}
/* if the server supports extended security then use SPNEGO */
- if (cli_state_capabilities(cli) & CAP_EXTENDED_SECURITY) {
- const char *remote_realm = cli_state_remote_realm(cli);
- ADS_STATUS status = cli_session_setup_spnego(cli, user, pass,
- workgroup,
- remote_realm);
- if (!ADS_ERR_OK(status)) {
- DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status)));
- return ads_ntstatus(status);
+ if (smb1cli_conn_capabilities(cli->conn) & CAP_EXTENDED_SECURITY) {
+ subreq = cli_session_setup_spnego_send(
+ state, ev, cli, user, pass, workgroup);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
+ tevent_req_set_callback(subreq, cli_session_setup_done_spnego,
+ req);
+ return req;
} else {
- NTSTATUS status;
-
/* otherwise do a NT1 style session setup */
- status = cli_session_setup_nt1(cli, user, pass, passlen,
- ntpass, ntpasslen, workgroup);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(3,("cli_session_setup: NT1 session setup "
- "failed: %s\n", nt_errstr(status)));
- return status;
+ if (lp_client_ntlmv2_auth() && lp_client_use_spnego()) {
+ /*
+ * Don't send an NTLMv2 response without NTLMSSP
+ * if we want to use spnego support
+ */
+ DEBUG(1, ("Server does not support EXTENDED_SECURITY "
+ " but 'client use spnego = yes"
+ " and 'client ntlmv2 auth = yes'\n"));
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = cli_session_setup_nt1_send(
+ state, ev, cli, user, pass, passlen, ntpass, ntpasslen,
+ workgroup);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
+ tevent_req_set_callback(subreq, cli_session_setup_done_nt1,
+ req);
+ return req;
}
- return NT_STATUS_OK;
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+}
+
+static void cli_session_setup_done_lanman2(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ NTSTATUS status;
+
+ status = cli_session_setup_lanman2_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static void cli_session_setup_done_spnego(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ ADS_STATUS status;
+
+ status = cli_session_setup_spnego_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status)));
+ tevent_req_nterror(req, ads_ntstatus(status));
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static void cli_session_setup_done_guest(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ NTSTATUS status;
+
+ status = cli_session_setup_guest_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static void cli_session_setup_done_plain(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ NTSTATUS status;
+
+ status = cli_session_setup_plain_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static void cli_session_setup_done_nt1(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ NTSTATUS status;
+
+ status = cli_session_setup_nt1_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("cli_session_setup: NT1 session setup "
+ "failed: %s\n", nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+NTSTATUS cli_session_setup_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_session_setup(struct cli_state *cli,
+ const char *user,
+ const char *pass, int passlen,
+ const char *ntpass, int ntpasslen,
+ const char *workgroup)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ev = samba_tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_session_setup_send(ev, 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_recv(req);
+ fail:
+ TALLOC_FREE(ev);
+ return status;
}
/****************************************************************************
static void cli_ulogoff_done(struct tevent_req *subreq);
-struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx,
+static struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli)
{
tevent_req_done(req);
}
-NTSTATUS cli_ulogoff_recv(struct tevent_req *req)
+static NTSTATUS cli_ulogoff_recv(struct tevent_req *req)
{
return tevent_req_simple_recv_ntstatus(req);
}
struct tevent_req *req;
NTSTATUS status = NT_STATUS_NO_MEMORY;
- if (cli_has_async_calls(cli)) {
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ status = smb2cli_logoff(cli->conn,
+ cli->timeout,
+ cli->smb2.session);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ smb2cli_session_set_id_and_flags(cli->smb2.session,
+ UINT64_MAX, 0);
+ return NT_STATUS_OK;
+ }
+
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
return NT_STATUS_INVALID_PARAMETER;
}
- ev = tevent_context_init(talloc_tos());
+ ev = samba_tevent_context_init(talloc_tos());
if (ev == NULL) {
goto fail;
}
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 tevent_context *ev,
struct cli_state *cli,
const char *share, const char *dev,
const char *pass, int passlen,
uint16_t *vwv;
char *tmp = NULL;
uint8_t *bytes;
- uint16_t sec_mode = cli_state_security_mode(cli);
+ uint16_t sec_mode = smb1cli_conn_server_security_mode(cli->conn);
+ uint16_t tcon_flags = 0;
*psmbreq = NULL;
* Non-encrypted passwords - convert to DOS codepage before
* encryption.
*/
- SMBencrypt(pass, cli_state_server_challenge(cli), p24);
+ SMBencrypt(pass, smb1cli_conn_server_challenge(cli->conn), p24);
passlen = 24;
pass = (const char *)p24;
} else {
uint8_t *tmp_pass;
if (!lp_client_plaintext_auth() && (*pass)) {
- DEBUG(1, ("Server requested plaintext "
+ DEBUG(1, ("Server requested PLAINTEXT "
"password but "
- "'client lanman auth = no' or 'client ntlmv2 auth = yes'\n"));
+ "'client plaintext auth = no' or 'client ntlmv2 auth = yes'\n"));
goto access_denied;
}
* Non-encrypted passwords - convert to DOS codepage
* before using.
*/
- tmp_pass = talloc_array(talloc_tos(), uint8, 0);
+ tmp_pass = talloc_array(talloc_tos(), uint8_t, 0);
if (tevent_req_nomem(tmp_pass, req)) {
return tevent_req_post(req, ev);
}
}
}
+ tcon_flags |= TCONX_FLAG_EXTENDED_RESPONSE;
+ tcon_flags |= TCONX_FLAG_EXTENDED_SIGNATURES;
+
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+2, 0, tcon_flags);
SSVAL(vwv+3, 0, passlen);
if (passlen && pass) {
* Add the sharename
*/
tmp = talloc_asprintf_strupper_m(talloc_tos(), "\\\\%s\\%s",
- cli_state_remote_name(cli), share);
+ smbXcli_conn_remote_name(cli->conn), share);
if (tmp == NULL) {
TALLOC_FREE(req);
return NULL;
}
- bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1,
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), tmp, strlen(tmp)+1,
NULL);
TALLOC_FREE(tmp);
}
struct tevent_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx,
- struct event_context *ev,
+ struct tevent_context *ev,
struct cli_state *cli,
const char *share, const char *dev,
const char *pass, int passlen)
if (subreq == NULL) {
return req;
}
- status = cli_smb_req_send(subreq);
+ status = smb1cli_req_chain_submit(&subreq, 1);
if (!NT_STATUS_IS_OK(status)) {
tevent_req_nterror(req, status);
return tevent_req_post(req, ev);
req, struct cli_tcon_andx_state);
struct cli_state *cli = state->cli;
uint8_t *in;
- char *inbuf;
+ uint8_t *inhdr;
uint8_t wct;
uint16_t *vwv;
uint32_t num_bytes;
uint8_t *bytes;
NTSTATUS status;
+ uint16_t optional_support = 0;
status = cli_smb_recv(subreq, state, &in, 0, &wct, &vwv,
&num_bytes, &bytes);
return;
}
- inbuf = (char *)in;
+ inhdr = in + NBT_HDR_SIZE;
if (num_bytes) {
if (clistr_pull_talloc(cli,
- inbuf,
- SVAL(inbuf, smb_flg2),
+ (const char *)inhdr,
+ SVAL(inhdr, HDR_FLG2),
&cli->dev,
bytes,
num_bytes,
}
}
- if ((cli_state_protocol(cli) >= PROTOCOL_NT1) && (num_bytes == 3)) {
+ if ((smbXcli_conn_protocol(cli->conn) >= PROTOCOL_NT1) && (num_bytes == 3)) {
/* almost certainly win95 - enable bug fixes */
cli->win95 = True;
}
* Avoids issues when connecting to Win9x boxes sharing files
*/
- cli->dfsroot = false;
+ if ((wct > 2) && (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_LANMAN2)) {
+ optional_support = SVAL(vwv+2, 0);
+ }
- if ((wct > 2) && (cli_state_protocol(cli) >= PROTOCOL_LANMAN2)) {
- cli->dfsroot = ((SVAL(vwv+2, 0) & SMB_SHARE_IN_DFS) != 0);
+ if (optional_support & SMB_EXTENDED_SIGNATURES) {
+ smb1cli_session_protect_session_key(cli->smb1.session);
}
- cli->smb1.tid = SVAL(inbuf,smb_tid);
+ smb1cli_tcon_set_values(state->cli->smb1.tcon,
+ SVAL(inhdr, HDR_TID),
+ optional_support,
+ 0, /* maximal_access */
+ 0, /* guest_maximal_access */
+ NULL, /* service */
+ NULL); /* fs_type */
+
tevent_req_done(req);
}
const char *dev, const char *pass, int passlen)
{
TALLOC_CTX *frame = talloc_stackframe();
- struct event_context *ev;
+ struct tevent_context *ev;
struct tevent_req *req;
- NTSTATUS status = NT_STATUS_OK;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
- if (cli_has_async_calls(cli)) {
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
/*
* Can't use sync call while an async call is in flight
*/
goto fail;
}
- ev = event_context_init(frame);
+ ev = samba_tevent_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);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
return status;
}
+struct cli_tree_connect_state {
+ struct cli_state *cli;
+};
+
+static struct tevent_req *cli_raw_tcon_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
+ const char *service, const char *pass, const char *dev);
+static NTSTATUS cli_raw_tcon_recv(struct tevent_req *req,
+ uint16_t *max_xmit, uint16_t *tid);
+
+static void cli_tree_connect_smb2_done(struct tevent_req *subreq);
+static void cli_tree_connect_andx_done(struct tevent_req *subreq);
+static void cli_tree_connect_raw_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_tree_connect_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
+ const char *share, const char *dev, const char *pass, int passlen)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_tree_connect_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_tree_connect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
+
+ cli->share = talloc_strdup(cli, share);
+ if (tevent_req_nomem(cli->share, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ char *unc;
+
+ cli->smb2.tcon = smbXcli_tcon_create(cli);
+ if (tevent_req_nomem(cli->smb2.tcon, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ unc = talloc_asprintf(state, "\\\\%s\\%s",
+ smbXcli_conn_remote_name(cli->conn),
+ share);
+ if (tevent_req_nomem(unc, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = smb2cli_tcon_send(state, ev, cli->conn, cli->timeout,
+ cli->smb2.session, cli->smb2.tcon,
+ 0, /* flags */
+ unc);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_tree_connect_smb2_done,
+ req);
+ return req;
+ }
+
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_LANMAN1) {
+ subreq = cli_tcon_andx_send(state, ev, cli, share, dev,
+ pass, passlen);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_tree_connect_andx_done,
+ req);
+ return req;
+ }
+
+ subreq = cli_raw_tcon_send(state, ev, cli, share, pass, dev);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_tree_connect_raw_done, req);
+
+ return req;
+}
+
+static void cli_tree_connect_smb2_done(struct tevent_req *subreq)
+{
+ tevent_req_simple_finish_ntstatus(
+ subreq, smb2cli_tcon_recv(subreq));
+}
+
+static void cli_tree_connect_andx_done(struct tevent_req *subreq)
+{
+ tevent_req_simple_finish_ntstatus(
+ subreq, cli_tcon_andx_recv(subreq));
+}
+
+static void cli_tree_connect_raw_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_tree_connect_state *state = tevent_req_data(
+ req, struct cli_tree_connect_state);
+ NTSTATUS status;
+ uint16_t max_xmit = 0;
+ uint16_t tid = 0;
+
+ status = cli_raw_tcon_recv(subreq, &max_xmit, &tid);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ smb1cli_tcon_set_values(state->cli->smb1.tcon,
+ tid,
+ 0, /* optional_support */
+ 0, /* maximal_access */
+ 0, /* guest_maximal_access */
+ NULL, /* service */
+ NULL); /* fs_type */
+
+ tevent_req_done(req);
+}
+
+static NTSTATUS cli_tree_connect_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_tree_connect(struct cli_state *cli, const char *share,
+ const char *dev, const char *pass, int passlen)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ev = samba_tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_tree_connect_send(ev, ev, cli, share, dev, pass, passlen);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_tree_connect_recv(req);
+fail:
+ TALLOC_FREE(ev);
+ return status;
+}
+
/****************************************************************************
Send a tree disconnect.
****************************************************************************/
static void cli_tdis_done(struct tevent_req *subreq);
-struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx,
+static struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli)
{
tevent_req_nterror(req, status);
return;
}
- state->cli->smb1.tid = UINT16_MAX;
+ cli_state_set_tid(state->cli, UINT16_MAX);
tevent_req_done(req);
}
-NTSTATUS cli_tdis_recv(struct tevent_req *req)
+static NTSTATUS cli_tdis_recv(struct tevent_req *req)
{
return tevent_req_simple_recv_ntstatus(req);
}
struct tevent_req *req;
NTSTATUS status = NT_STATUS_NO_MEMORY;
- if (cli_has_async_calls(cli)) {
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ return smb2cli_tdis(cli->conn,
+ cli->timeout,
+ cli->smb2.session,
+ cli->smb2.tcon);
+ }
+
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
return NT_STATUS_INVALID_PARAMETER;
}
- ev = tevent_context_init(talloc_tos());
+ ev = samba_tevent_context_init(talloc_tos());
if (ev == NULL) {
goto fail;
}
return status;
}
-/****************************************************************************
- Send a negprot command.
-****************************************************************************/
-
-struct cli_negprot_state {
- struct cli_state *cli;
- enum protocol_types max_protocol;
+struct cli_connect_sock_state {
+ const char **called_names;
+ const char **calling_names;
+ int *called_types;
+ int fd;
+ uint16_t port;
};
-static void cli_negprot_done(struct tevent_req *subreq);
+static void cli_connect_sock_done(struct tevent_req *subreq);
-struct tevent_req *cli_negprot_send(TALLOC_CTX *mem_ctx,
- struct event_context *ev,
- struct cli_state *cli,
- enum protocol_types max_protocol)
+/*
+ * Async only if we don't have to look up the name, i.e. "pss" is set with a
+ * nonzero address.
+ */
+
+static struct tevent_req *cli_connect_sock_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ const char *host, int name_type, const struct sockaddr_storage *pss,
+ const char *myname, uint16_t port)
{
struct tevent_req *req, *subreq;
- struct cli_negprot_state *state;
- uint8_t *bytes = NULL;
- int numprots;
- enum protocol_types tmp_protocol;
+ struct cli_connect_sock_state *state;
+ const char *prog;
+ struct sockaddr_storage *addrs;
+ unsigned i, num_addrs;
+ NTSTATUS status;
- req = tevent_req_create(mem_ctx, &state, struct cli_negprot_state);
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_connect_sock_state);
if (req == NULL) {
return NULL;
}
- state->cli = cli;
- state->max_protocol = max_protocol;
- /* setup the protocol strings */
- for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
- uint8_t c = 2;
- if (prots[numprots].prot > state->max_protocol) {
- break;
+ prog = getenv("LIBSMB_PROG");
+ if (prog != NULL) {
+ state->fd = sock_exec(prog);
+ if (state->fd == -1) {
+ status = map_nt_error_from_unix(errno);
+ tevent_req_nterror(req, status);
+ } else {
+ state->port = 0;
+ tevent_req_done(req);
}
- 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);
+ }
+
+ if ((pss == NULL) || is_zero_addr(pss)) {
+
+ /*
+ * Here we cheat. resolve_name_list is not async at all. So
+ * this call will only be really async if the name lookup has
+ * been done externally.
+ */
+
+ status = resolve_name_list(state, host, name_type,
+ &addrs, &num_addrs);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
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)) {
+ } else {
+ addrs = talloc_array(state, struct sockaddr_storage, 1);
+ if (tevent_req_nomem(addrs, req)) {
return tevent_req_post(req, ev);
}
+ addrs[0] = *pss;
+ num_addrs = 1;
}
- tmp_protocol = cli->conn.protocol;
- cli->conn.protocol = state->max_protocol;
- subreq = cli_smb_send(state, ev, cli, SMBnegprot, 0, 0, NULL,
- talloc_get_size(bytes), bytes);
- cli->conn.protocol = tmp_protocol;
+ state->called_names = talloc_array(state, const char *, num_addrs);
+ if (tevent_req_nomem(state->called_names, req)) {
+ return tevent_req_post(req, ev);
+ }
+ state->called_types = talloc_array(state, int, num_addrs);
+ if (tevent_req_nomem(state->called_types, req)) {
+ return tevent_req_post(req, ev);
+ }
+ state->calling_names = talloc_array(state, const char *, num_addrs);
+ if (tevent_req_nomem(state->calling_names, req)) {
+ return tevent_req_post(req, ev);
+ }
+ for (i=0; i<num_addrs; i++) {
+ state->called_names[i] = host;
+ state->called_types[i] = name_type;
+ state->calling_names[i] = myname;
+ }
+
+ subreq = smbsock_any_connect_send(
+ state, ev, addrs, state->called_names, state->called_types,
+ state->calling_names, NULL, num_addrs, port);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
- tevent_req_set_callback(subreq, cli_negprot_done, req);
+ tevent_req_set_callback(subreq, cli_connect_sock_done, req);
return req;
}
-static void cli_negprot_done(struct tevent_req *subreq)
+static void cli_connect_sock_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 flags;
- uint8_t wct;
- uint16_t *vwv;
- uint32_t num_bytes;
- uint8_t *bytes;
+ struct cli_connect_sock_state *state = tevent_req_data(
+ req, struct cli_connect_sock_state);
NTSTATUS status;
- uint16_t protnum;
- uint8_t *inbuf;
- uint32_t client_capabilities = cli->conn.smb1.client.capabilities;
- uint32_t both_capabilities;
- uint32_t server_capabilities = 0;
- uint32_t capabilities;
- uint32_t client_max_xmit = cli->conn.smb1.client.max_xmit;
- uint32_t server_max_xmit = 0;
- uint32_t max_xmit;
- uint32_t server_max_mux = 0;
- uint16_t server_security_mode = 0;
- uint32_t server_session_key = 0;
- bool server_readbraw = false;
- bool server_writebraw = false;
- bool server_lockread = false;
- bool server_writeunlock = false;
- struct GUID server_guid = GUID_zero();
- DATA_BLOB server_gss_blob = data_blob_null;
- uint8_t server_challenge[8];
- char *server_workgroup = NULL;
- char *server_name = NULL;
- int server_time_zone = 0;
- time_t server_system_time = 0;
- enum protocol_types protocol;
-
- ZERO_STRUCT(server_challenge);
-
- status = cli_smb_recv(subreq, state, &inbuf, 1, &wct, &vwv,
- &num_bytes, &bytes);
- TALLOC_FREE(subreq);
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
- }
-
- flags = CVAL(inbuf, smb_flg);
- protnum = SVAL(vwv, 0);
-
- if ((protnum >= ARRAY_SIZE(prots))
- || (prots[protnum].prot > state->max_protocol)) {
- tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ status = smbsock_any_connect_recv(subreq, &state->fd, NULL,
+ &state->port);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
return;
}
+ set_socket_options(state->fd, lp_socket_options());
+ tevent_req_done(req);
+}
- protocol = prots[protnum].prot;
-
- if ((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"));
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
- return;
- }
+static NTSTATUS cli_connect_sock_recv(struct tevent_req *req,
+ int *pfd, uint16_t *pport)
+{
+ struct cli_connect_sock_state *state = tevent_req_data(
+ req, struct cli_connect_sock_state);
+ NTSTATUS status;
- if (flags & FLAG_SUPPORT_LOCKREAD) {
- server_lockread = true;
- server_writeunlock = true;
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
}
+ *pfd = state->fd;
+ *pport = state->port;
+ return NT_STATUS_OK;
+}
- if (protocol >= PROTOCOL_NT1) {
- struct timespec ts;
- const char *client_signing = NULL;
- bool server_mandatory;
- bool server_allowed;
- const char *server_signing = NULL;
- bool ok;
- uint8_t key_len;
-
- if (wct != 0x11) {
- tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- /* NT protocol */
- server_security_mode = CVAL(vwv + 1, 0);
- server_max_mux = SVAL(vwv + 1, 1);
- server_max_xmit = IVAL(vwv + 3, 1);
- server_session_key = IVAL(vwv + 7, 1);
- server_time_zone = SVALS(vwv + 15, 1);
- server_time_zone *= 60;
- /* this time arrives in real GMT */
- ts = interpret_long_date(((char *)(vwv+11))+1);
- server_system_time = ts.tv_sec;
- server_capabilities = IVAL(vwv + 9, 1);
-
- key_len = CVAL(vwv + 16, 1);
-
- if (server_capabilities & CAP_RAW_MODE) {
- server_readbraw = true;
- server_writebraw = true;
- }
- if (server_capabilities & CAP_LOCK_AND_READ) {
- server_lockread = true;
- }
-
- if (server_capabilities & CAP_EXTENDED_SECURITY) {
- DATA_BLOB blob1, blob2;
-
- if (num_bytes < 16) {
- tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- blob1 = data_blob_const(bytes, 16);
- GUID_from_data_blob(&blob1, &server_guid);
-
- blob1 = data_blob_const(bytes+16, num_bytes-16);
- blob2 = data_blob_dup_talloc(state, blob1);
- if (blob1.length > 0 &&
- tevent_req_nomem(blob2.data, req)) {
- return;
- }
- server_gss_blob = blob2;
- } else {
- DATA_BLOB blob1, blob2;
- ssize_t ret = 0;
+struct cli_connect_nb_state {
+ const char *desthost;
+ int signing_state;
+ int flags;
+ struct cli_state *cli;
+};
- if (num_bytes < key_len) {
- tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
+static void cli_connect_nb_done(struct tevent_req *subreq);
- if (key_len != 0 && key_len != 8) {
- tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
+static struct tevent_req *cli_connect_nb_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ const char *host, const struct sockaddr_storage *dest_ss,
+ uint16_t port, int name_type, const char *myname,
+ int signing_state, int flags)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_connect_nb_state *state;
- if (key_len == 8) {
- memcpy(server_challenge, bytes, 8);
- }
+ req = tevent_req_create(mem_ctx, &state, struct cli_connect_nb_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->signing_state = signing_state;
+ state->flags = flags;
- blob1 = data_blob_const(bytes+key_len, num_bytes-key_len);
- blob2 = data_blob_const(bytes+key_len, num_bytes-key_len);
- if (blob1.length > 0) {
- ret = pull_string_talloc(state,
- (char *)inbuf,
- SVAL(inbuf, smb_flg2),
- &server_workgroup,
- blob1.data,
- blob1.length,
- STR_TERMINATE|
- STR_UNICODE|
- STR_NOALIGN);
- if (ret == -1) {
- tevent_req_oom(req);
- return;
- }
- }
+ if (host != NULL) {
+ char *p = strchr(host, '#');
- blob2.data += ret;
- blob2.length -= ret;
- if (blob2.length > 0) {
- ret = pull_string_talloc(state,
- (char *)inbuf,
- SVAL(inbuf, smb_flg2),
- &server_name,
- blob2.data,
- blob2.length,
- STR_TERMINATE|
- STR_UNICODE|
- STR_NOALIGN);
- if (ret == -1) {
- tevent_req_oom(req);
- return;
- }
+ if (p != NULL) {
+ name_type = strtol(p+1, NULL, 16);
+ host = talloc_strndup(state, host, p - host);
+ if (tevent_req_nomem(host, req)) {
+ return tevent_req_post(req, ev);
}
}
- client_signing = "disabled";
- if (client_is_signing_allowed(cli)) {
- client_signing = "allowed";
- }
- if (client_is_signing_mandatory(cli)) {
- client_signing = "required";
- }
-
- server_signing = "not supported";
-
- server_allowed = false;
- if (server_security_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
- server_signing = "supported";
- server_allowed = true;
- }
-
- server_mandatory = false;
- if (server_security_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
- server_signing = "required";
- server_mandatory = true;
- }
-
- ok = cli_set_signing_negotiated(cli,
- server_allowed,
- server_mandatory);
- if (!ok) {
- DEBUG(1,("cli_negprot: SMB signing is required, "
- "but client[%s] and server[%s] mismatch\n",
- client_signing, server_signing));
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
- return;
- }
-
- } else if (protocol >= PROTOCOL_LANMAN1) {
- DATA_BLOB blob1;
- ssize_t ret = 0;
- uint16_t key_len;
-
- if (wct != 0x0D) {
- tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- server_security_mode = SVAL(vwv + 1, 0);
- server_max_xmit = SVAL(vwv + 2, 0);
- server_max_mux = SVAL(vwv + 3, 0);
- server_readbraw = ((SVAL(vwv + 5, 0) & 0x1) != 0);
- server_writebraw = ((SVAL(vwv + 5, 0) & 0x2) != 0);
- server_session_key = IVAL(vwv + 6, 0);
- server_time_zone = SVALS(vwv + 10, 0);
- server_time_zone *= 60;
- /* this time is converted to GMT by make_unix_date */
- server_system_time = make_unix_date(
- (char *)(vwv + 8), server_time_zone);
- key_len = SVAL(vwv + 11, 0);
-
- if (num_bytes < key_len) {
- tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- if (key_len != 0 && key_len != 8) {
- tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- if (key_len == 8) {
- memcpy(server_challenge, bytes, 8);
- }
-
- blob1 = data_blob_const(bytes+key_len, num_bytes-key_len);
- if (blob1.length > 0) {
- ret = pull_string_talloc(state,
- (char *)inbuf,
- SVAL(inbuf, smb_flg2),
- &server_workgroup,
- blob1.data,
- blob1.length,
- STR_TERMINATE|
- STR_ASCII);
- if (ret == -1) {
- tevent_req_oom(req);
- return;
- }
- }
+ state->desthost = host;
} else {
- /* the old core protocol */
- server_time_zone = get_time_zone(time(NULL));
- server_system_time = 0;
- server_max_xmit = 1024;
- server_max_mux = 1;
- server_security_mode = 0;
+ state->desthost = print_canonical_sockaddr(state, dest_ss);
+ if (tevent_req_nomem(state->desthost, req)) {
+ return tevent_req_post(req, ev);
+ }
}
- if (server_max_xmit < 1024) {
- tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
+ subreq = cli_connect_sock_send(state, ev, host, name_type, dest_ss,
+ myname, port);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
+ tevent_req_set_callback(subreq, cli_connect_nb_done, req);
+ return req;
+}
- if (server_max_mux < 1) {
- tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+static void cli_connect_nb_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_connect_nb_state *state = tevent_req_data(
+ req, struct cli_connect_nb_state);
+ NTSTATUS status;
+ int fd = 0;
+ uint16_t port;
+
+ status = cli_connect_sock_recv(subreq, &fd, &port);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
return;
}
- /*
- * Now calculate the negotiated capabilities
- * based on the mask for:
- * - client only flags
- * - flags used in both directions
- * - server only flags
- */
- both_capabilities = client_capabilities & server_capabilities;
- capabilities = client_capabilities & SMB_CAP_CLIENT_MASK;
- capabilities |= both_capabilities & SMB_CAP_BOTH_MASK;
- capabilities |= server_capabilities & SMB_CAP_SERVER_MASK;
-
- max_xmit = MIN(client_max_xmit, server_max_xmit);
-
- if (server_workgroup) {
- cli->server_domain = talloc_strdup(cli, server_workgroup);
- if (tevent_req_nomem(cli->server_domain, req)) {
- return;
- }
+ state->cli = cli_state_create(state, fd, state->desthost, NULL,
+ state->signing_state, state->flags);
+ if (tevent_req_nomem(state->cli, req)) {
+ close(fd);
+ return;
}
-
- cli->conn.protocol = protocol;
-
- cli->conn.smb1.server.capabilities = server_capabilities;
- cli->conn.smb1.capabilities = capabilities;
-
- cli->conn.smb1.server.max_xmit = server_max_xmit;
- cli->conn.smb1.max_xmit = max_xmit;
-
- cli->conn.smb1.server.max_mux = server_max_mux;
-
- cli->conn.smb1.server.security_mode = server_security_mode;
-
- cli->conn.smb1.server.readbraw = server_readbraw;
- cli->conn.smb1.server.writebraw = server_writebraw;
- cli->conn.smb1.server.lockread = server_lockread;
- cli->conn.smb1.server.writeunlock = server_writeunlock;
-
- cli->conn.smb1.server.session_key = server_session_key;
-
- talloc_steal(cli, server_gss_blob.data);
- cli->conn.smb1.server.gss_blob = server_gss_blob;
- cli->conn.smb1.server.guid = server_guid;
- memcpy(cli->conn.smb1.server.challenge, server_challenge, 8);
- cli->conn.smb1.server.workgroup = talloc_move(cli, &server_workgroup);
- cli->conn.smb1.server.name = talloc_move(cli, &server_name);
-
- cli->conn.smb1.server.time_zone = server_time_zone;
- cli->conn.smb1.server.system_time = server_system_time;
-
tevent_req_done(req);
}
-NTSTATUS cli_negprot_recv(struct tevent_req *req)
+static NTSTATUS cli_connect_nb_recv(struct tevent_req *req,
+ struct cli_state **pcli)
{
- return tevent_req_simple_recv_ntstatus(req);
+ struct cli_connect_nb_state *state = tevent_req_data(
+ req, struct cli_connect_nb_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ *pcli = talloc_move(NULL, &state->cli);
+ return NT_STATUS_OK;
}
-NTSTATUS cli_negprot(struct cli_state *cli, enum protocol_types max_protocol)
+NTSTATUS cli_connect_nb(const char *host, const struct sockaddr_storage *dest_ss,
+ uint16_t port, int name_type, const char *myname,
+ int signing_state, int flags, struct cli_state **pcli)
{
- TALLOC_CTX *frame = talloc_stackframe();
- struct event_context *ev;
+ struct tevent_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;
- }
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
- ev = event_context_init(frame);
+ ev = samba_tevent_context_init(talloc_tos());
if (ev == NULL) {
- status = NT_STATUS_NO_MEMORY;
goto fail;
}
-
- req = cli_negprot_send(frame, ev, cli, max_protocol);
+ req = cli_connect_nb_send(ev, ev, host, dest_ss, port, name_type,
+ myname, signing_state, flags);
if (req == NULL) {
- status = NT_STATUS_NO_MEMORY;
goto fail;
}
-
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
+ if (!tevent_req_set_endtime(req, ev, timeval_current_ofs(20, 0))) {
goto fail;
}
-
- status = cli_negprot_recv(req);
- fail:
- TALLOC_FREE(frame);
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_connect_nb_recv(req, pcli);
+fail:
+ TALLOC_FREE(ev);
return status;
}
-static NTSTATUS cli_connect_sock(const char *host, int name_type,
- const struct sockaddr_storage *pss,
- const char *myname, uint16_t port,
- int sec_timeout, int *pfd, uint16_t *pport)
-{
- TALLOC_CTX *frame = talloc_stackframe();
- const char *prog;
- unsigned int i, num_addrs;
- const char **called_names;
- const char **calling_names;
- int *called_types;
- NTSTATUS status;
- int fd;
+struct cli_start_connection_state {
+ struct tevent_context *ev;
+ struct cli_state *cli;
+ int min_protocol;
+ int max_protocol;
+};
- prog = getenv("LIBSMB_PROG");
- if (prog != NULL) {
- fd = sock_exec(prog);
- if (fd == -1) {
- return map_nt_error_from_unix(errno);
- }
- port = 0;
- goto done;
- }
+static void cli_start_connection_connected(struct tevent_req *subreq);
+static void cli_start_connection_done(struct tevent_req *subreq);
- if ((pss == NULL) || is_zero_addr(pss)) {
- struct sockaddr_storage *addrs;
- status = resolve_name_list(talloc_tos(), host, name_type,
- &addrs, &num_addrs);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
- pss = addrs;
- } else {
- num_addrs = 1;
+/**
+ establishes a connection to after the negprot.
+ @param output_cli A fully initialised cli structure, non-null only on success
+ @param dest_host The netbios name of the remote host
+ @param dest_ss (optional) The the destination IP, NULL for name based lookup
+ @param port (optional) The destination port (0 for default)
+*/
+
+static struct tevent_req *cli_start_connection_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ const char *my_name, const char *dest_host,
+ const struct sockaddr_storage *dest_ss, int port,
+ int signing_state, int flags)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_start_connection_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_start_connection_state);
+ if (req == NULL) {
+ return NULL;
}
+ state->ev = ev;
- called_names = talloc_array(talloc_tos(), const char *, num_addrs);
- if (called_names == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
- called_types = talloc_array(talloc_tos(), int, num_addrs);
- if (called_types == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
+ if (signing_state == SMB_SIGNING_IPC_DEFAULT) {
+ state->min_protocol = lp_client_ipc_min_protocol();
+ state->max_protocol = lp_client_ipc_max_protocol();
+ } else {
+ state->min_protocol = lp_client_min_protocol();
+ state->max_protocol = lp_client_max_protocol();
}
- calling_names = talloc_array(talloc_tos(), const char *, num_addrs);
- if (calling_names == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
+
+ subreq = cli_connect_nb_send(state, ev, dest_host, dest_ss, port,
+ 0x20, my_name, signing_state, flags);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
- for (i=0; i<num_addrs; i++) {
- called_names[i] = host;
- called_types[i] = name_type;
- calling_names[i] = myname;
+ tevent_req_set_callback(subreq, cli_start_connection_connected, req);
+ return req;
+}
+
+static void cli_start_connection_connected(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_start_connection_state *state = tevent_req_data(
+ req, struct cli_start_connection_state);
+ NTSTATUS status;
+
+ status = cli_connect_nb_recv(subreq, &state->cli);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
}
- status = smbsock_any_connect(pss, called_names, called_types,
- calling_names, NULL, num_addrs, port,
- sec_timeout, &fd, NULL, &port);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
+
+ subreq = smbXcli_negprot_send(state, state->ev, state->cli->conn,
+ state->cli->timeout,
+ state->min_protocol,
+ state->max_protocol);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
}
- set_socket_options(fd, lp_socket_options());
-done:
- *pfd = fd;
- *pport = port;
- status = NT_STATUS_OK;
-fail:
- TALLOC_FREE(frame);
- return status;
+ tevent_req_set_callback(subreq, cli_start_connection_done, req);
}
-NTSTATUS cli_connect_nb(const char *host, const struct sockaddr_storage *dest_ss,
- uint16_t port, int name_type, const char *myname,
- int signing_state, int flags, struct cli_state **pcli)
+static void cli_start_connection_done(struct tevent_req *subreq)
{
- TALLOC_CTX *frame = talloc_stackframe();
- struct cli_state *cli;
- NTSTATUS status = NT_STATUS_NO_MEMORY;
- int fd = -1;
- char *desthost;
- char *p;
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_start_connection_state *state = tevent_req_data(
+ req, struct cli_start_connection_state);
+ NTSTATUS status;
- desthost = talloc_strdup(talloc_tos(), host);
- if (desthost == NULL) {
- goto fail;
+ status = smbXcli_negprot_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
}
- p = strchr(host, '#');
- if (p != NULL) {
- name_type = strtol(p+1, NULL, 16);
- host = talloc_strndup(talloc_tos(), host, p - host);
- if (host == NULL) {
- goto fail;
- }
+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+ /* Ensure we ask for some initial credits. */
+ smb2cli_conn_set_max_credits(state->cli->conn,
+ DEFAULT_SMB2_MAX_CREDITS);
}
- status = cli_connect_sock(host, name_type, dest_ss, myname, port,
- 20, &fd, &port);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
+ tevent_req_done(req);
+}
- cli = cli_state_create(NULL, fd, desthost, NULL, signing_state, flags);
- if (cli == NULL) {
- close(fd);
- fd = -1;
- goto fail;
+static NTSTATUS cli_start_connection_recv(struct tevent_req *req,
+ struct cli_state **output_cli)
+{
+ struct cli_start_connection_state *state = tevent_req_data(
+ req, struct cli_start_connection_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
}
+ *output_cli = state->cli;
- *pcli = cli;
- status = NT_STATUS_OK;
-fail:
- TALLOC_FREE(frame);
- return status;
+ return NT_STATUS_OK;
}
-/**
- establishes a connection to after the negprot.
- @param output_cli A fully initialised cli structure, non-null only on success
- @param dest_host The netbios name of the remote host
- @param dest_ss (optional) The the destination IP, NULL for name based lookup
- @param port (optional) The destination port (0 for default)
-*/
NTSTATUS cli_start_connection(struct cli_state **output_cli,
const char *my_name,
const char *dest_host,
const struct sockaddr_storage *dest_ss, int port,
int signing_state, int flags)
{
- NTSTATUS nt_status;
- struct cli_state *cli;
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
- nt_status = cli_connect_nb(dest_host, dest_ss, port, 0x20, my_name,
- signing_state, flags, &cli);
- if (!NT_STATUS_IS_OK(nt_status)) {
- DEBUG(10, ("cli_connect_nb failed: %s\n",
- nt_errstr(nt_status)));
- return nt_status;
+ ev = samba_tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
}
-
- nt_status = cli_negprot(cli, PROTOCOL_NT1);
- if (!NT_STATUS_IS_OK(nt_status)) {
- DEBUG(1, ("failed negprot: %s\n", nt_errstr(nt_status)));
- cli_shutdown(cli);
- return nt_status;
+ req = cli_start_connection_send(ev, ev, my_name, dest_host, dest_ss,
+ port, signing_state, flags);
+ if (req == NULL) {
+ goto fail;
}
-
- *output_cli = cli;
- return NT_STATUS_OK;
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_start_connection_recv(req, output_cli);
+fail:
+ TALLOC_FREE(ev);
+ return status;
}
-
/**
establishes a connection right up to doing tconX, password specified.
@param output_cli A fully initialised cli structure, non-null only on success
@param password User's password, unencrypted unix string.
*/
-NTSTATUS cli_full_connection(struct cli_state **output_cli,
- const char *my_name,
- const char *dest_host,
- const struct sockaddr_storage *dest_ss, int port,
- const char *service, const char *service_type,
- const char *user, const char *domain,
- const char *password, int flags,
- int signing_state)
+struct cli_full_connection_state {
+ struct tevent_context *ev;
+ const char *service;
+ const char *service_type;
+ const char *user;
+ const char *domain;
+ const char *password;
+ int pw_len;
+ int flags;
+ struct cli_state *cli;
+};
+
+static int cli_full_connection_state_destructor(
+ struct cli_full_connection_state *s);
+static void cli_full_connection_started(struct tevent_req *subreq);
+static void cli_full_connection_sess_set_up(struct tevent_req *subreq);
+static void cli_full_connection_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_full_connection_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ const char *my_name, const char *dest_host,
+ const struct sockaddr_storage *dest_ss, int port,
+ const char *service, const char *service_type,
+ const char *user, const char *domain,
+ const char *password, int flags, int signing_state)
{
- NTSTATUS nt_status;
- struct cli_state *cli = NULL;
- int pw_len = password ? strlen(password)+1 : 0;
+ struct tevent_req *req, *subreq;
+ struct cli_full_connection_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_full_connection_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ talloc_set_destructor(state, cli_full_connection_state_destructor);
- *output_cli = NULL;
+ state->ev = ev;
+ state->service = service;
+ state->service_type = service_type;
+ state->user = user;
+ state->domain = domain;
+ state->password = password;
+ state->flags = flags;
- if (password == NULL) {
- password = "";
+ state->pw_len = state->password ? strlen(state->password)+1 : 0;
+ if (state->password == NULL) {
+ state->password = "";
}
- nt_status = cli_start_connection(&cli, my_name, dest_host,
- dest_ss, port, signing_state,
- flags);
+ subreq = cli_start_connection_send(
+ state, ev, my_name, dest_host, dest_ss, port,
+ signing_state, flags);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_full_connection_started, req);
+ return req;
+}
- if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
+static int cli_full_connection_state_destructor(
+ struct cli_full_connection_state *s)
+{
+ if (s->cli != NULL) {
+ cli_shutdown(s->cli);
+ s->cli = NULL;
}
+ return 0;
+}
- nt_status = cli_session_setup(cli, user, password, pw_len, password,
- pw_len, domain);
- if (!NT_STATUS_IS_OK(nt_status)) {
+static void cli_full_connection_started(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_full_connection_state *state = tevent_req_data(
+ req, struct cli_full_connection_state);
+ NTSTATUS status;
- if (!(flags & CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK)) {
- DEBUG(1,("failed session setup with %s\n",
- nt_errstr(nt_status)));
- cli_shutdown(cli);
- return nt_status;
- }
+ status = cli_start_connection_recv(subreq, &state->cli);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ subreq = cli_session_setup_send(
+ state, state->ev, state->cli, state->user,
+ state->password, state->pw_len, state->password, state->pw_len,
+ state->domain);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, cli_full_connection_sess_set_up, req);
+}
+
+static void cli_full_connection_sess_set_up(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_full_connection_state *state = tevent_req_data(
+ req, struct cli_full_connection_state);
+ NTSTATUS status;
+
+ status = cli_session_setup_recv(subreq);
+ TALLOC_FREE(subreq);
- nt_status = cli_session_setup(cli, "", "", 0, "", 0, domain);
- if (!NT_STATUS_IS_OK(nt_status)) {
- DEBUG(1,("anonymous failed session setup with %s\n",
- nt_errstr(nt_status)));
- cli_shutdown(cli);
- return nt_status;
+ if (!NT_STATUS_IS_OK(status) &&
+ (state->flags & CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK)) {
+
+ state->flags &= ~CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK;
+
+ subreq = cli_session_setup_send(
+ state, state->ev, state->cli, "", "", 0, "", 0,
+ state->domain);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
}
+ tevent_req_set_callback(
+ subreq, cli_full_connection_sess_set_up, req);
+ return;
}
- if (service) {
- nt_status = cli_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)) {
- nt_status = NT_STATUS_UNSUCCESSFUL;
- }
- return nt_status;
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (state->service != NULL) {
+ subreq = cli_tree_connect_send(
+ state, state->ev, state->cli,
+ state->service, state->service_type,
+ state->password, state->pw_len);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
}
+ tevent_req_set_callback(subreq, cli_full_connection_done, req);
+ return;
}
- nt_status = cli_init_creds(cli, user, domain, password);
- if (!NT_STATUS_IS_OK(nt_status)) {
- cli_shutdown(cli);
- return nt_status;
+ tevent_req_done(req);
+}
+
+static void cli_full_connection_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ NTSTATUS status;
+
+ status = cli_tree_connect_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
}
- *output_cli = cli;
+ tevent_req_done(req);
+}
+
+NTSTATUS cli_full_connection_recv(struct tevent_req *req,
+ struct cli_state **output_cli)
+{
+ struct cli_full_connection_state *state = tevent_req_data(
+ req, struct cli_full_connection_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ *output_cli = state->cli;
+ talloc_set_destructor(state, NULL);
return NT_STATUS_OK;
}
+NTSTATUS cli_full_connection(struct cli_state **output_cli,
+ const char *my_name,
+ const char *dest_host,
+ const struct sockaddr_storage *dest_ss, int port,
+ const char *service, const char *service_type,
+ const char *user, const char *domain,
+ const char *password, int flags,
+ int signing_state)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_full_connection_send(
+ ev, ev, my_name, dest_host, dest_ss, port, service,
+ service_type, user, domain, password, flags, signing_state);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_full_connection_recv(req, output_cli);
+ fail:
+ TALLOC_FREE(ev);
+ return status;
+}
+
/****************************************************************************
Send an old style tcon.
****************************************************************************/
-NTSTATUS cli_raw_tcon(struct cli_state *cli,
- const char *service, const char *pass, const char *dev,
- uint16 *max_xmit, uint16 *tid)
-{
- struct tevent_req *req;
+struct cli_raw_tcon_state {
uint16_t *ret_vwv;
+};
+
+static void cli_raw_tcon_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_raw_tcon_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
+ const char *service, const char *pass, const char *dev)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_raw_tcon_state *state;
uint8_t *bytes;
- NTSTATUS status;
+
+ req = tevent_req_create(mem_ctx, &state, struct cli_raw_tcon_state);
+ if (req == NULL) {
+ return NULL;
+ }
if (!lp_client_plaintext_auth() && (*pass)) {
- DEBUG(1, ("Server requested plaintext password but 'client "
- "plaintext auth' is disabled\n"));
- return NT_STATUS_ACCESS_DENIED;
+ DEBUG(1, ("Server requested PLAINTEXT password but 'client plaintext auth = no'"
+ " or 'client ntlmv2 auth = yes'\n"));
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return tevent_req_post(req, ev);
}
- bytes = talloc_array(talloc_tos(), uint8_t, 0);
+ bytes = talloc_array(state, uint8_t, 0);
bytes = smb_bytes_push_bytes(bytes, 4, NULL, 0);
- bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
service, strlen(service)+1, NULL);
bytes = smb_bytes_push_bytes(bytes, 4, NULL, 0);
- bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
pass, strlen(pass)+1, NULL);
bytes = smb_bytes_push_bytes(bytes, 4, NULL, 0);
- bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
dev, strlen(dev)+1, NULL);
- status = cli_smb(talloc_tos(), cli, SMBtcon, 0, 0, NULL,
- talloc_get_size(bytes), bytes, &req,
- 2, NULL, &ret_vwv, NULL, NULL);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = cli_smb_send(state, ev, cli, SMBtcon, 0, 0, NULL,
+ talloc_get_size(bytes), bytes);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_raw_tcon_done, req);
+ return req;
+}
+
+static void cli_raw_tcon_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_raw_tcon_state *state = tevent_req_data(
+ req, struct cli_raw_tcon_state);
+ NTSTATUS status;
+
+ status = cli_smb_recv(subreq, state, NULL, 2, NULL, &state->ret_vwv,
+ NULL, NULL);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
}
+ tevent_req_done(req);
+}
- *max_xmit = SVAL(ret_vwv + 0, 0);
- *tid = SVAL(ret_vwv + 1, 0);
+static NTSTATUS cli_raw_tcon_recv(struct tevent_req *req,
+ uint16_t *max_xmit, uint16_t *tid)
+{
+ struct cli_raw_tcon_state *state = tevent_req_data(
+ req, struct cli_raw_tcon_state);
+ NTSTATUS status;
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ *max_xmit = SVAL(state->ret_vwv + 0, 0);
+ *tid = SVAL(state->ret_vwv + 1, 0);
return NT_STATUS_OK;
}
+NTSTATUS cli_raw_tcon(struct cli_state *cli,
+ const char *service, const char *pass, const char *dev,
+ uint16_t *max_xmit, uint16_t *tid)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_raw_tcon_send(ev, ev, cli, service, pass, dev);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_raw_tcon_recv(req, max_xmit, tid);
+fail:
+ TALLOC_FREE(ev);
+ return status;
+}
+
/* Return a cli_state pointing at the IPC$ share for the given server */
struct cli_state *get_ipc_connect(char *server,
if (!NT_STATUS_IS_OK(status)) {
DEBUG(99, ("No master browsers responded: %s\n",
nt_errstr(status)));
- return False;
+ return NULL;
}
for (i = 0; i < count; i++) {