#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 "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"
+#include "smb2cli.h"
#define STAR_SMBSERVER "*SMBSERVER"
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 "
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);
struct tevent_req *req;
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
*/
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:
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);
struct tevent_req *req;
NTSTATUS status = NT_STATUS_OK;
- 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
*/
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);
struct tevent_req *req;
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
*/
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);
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;
}
struct tevent_req *req;
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
*/
uint16_t vwv[12];
uint8_t *buf;
+ DATA_BLOB smb2_blob;
+ struct iovec *recv_iov;
+
NTSTATUS status;
char *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);
uint8_t *inbuf;
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, &inbuf, 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);
+
+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+ goto next;
+ }
state->inbuf = (char *)inbuf;
cli_state_set_uid(state->cli, SVAL(inbuf, smb_uid));
}
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)
+ char **pinbuf,
+ struct iovec **precv_iov)
{
struct cli_sesssetup_blob_state *state = tevent_req_data(
req, struct cli_sesssetup_blob_state);
NTSTATUS status;
char *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;
}
state->negTokenTarg.length);
#endif
+ 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);
+ }
+ }
+
subreq = cli_sesssetup_blob_send(state, ev, cli, state->negTokenTarg);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
struct cli_session_setup_kerberos_state *state = tevent_req_data(
req, struct cli_session_setup_kerberos_state);
char *inbuf = NULL;
+ struct iovec *recv_iov = NULL;
NTSTATUS status;
- status = cli_sesssetup_blob_recv(subreq, talloc_tos(), NULL, &inbuf);
+ status = cli_sesssetup_blob_recv(subreq, state,
+ NULL, &inbuf, &recv_iov);
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
tevent_req_nterror(req, status);
cli_set_session_key(state->cli, state->session_key_krb5);
- if (cli_simple_set_signing(state->cli, state->session_key_krb5,
- data_blob_null)
- && !cli_check_sign_mac(state->cli, inbuf, 1)) {
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
- return;
+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+ struct smbXcli_session *session = state->cli->smb2.session;
+ status = smb2cli_session_set_session_key(session,
+ state->session_key_krb5,
+ recv_iov);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ } else {
+ if (smb1cli_conn_activate_signing(state->cli->conn, state->session_key_krb5,
+ data_blob_null)
+ && !smb1cli_conn_check_signing(state->cli->conn, (uint8_t *)inbuf, 1)) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
}
tevent_req_done(req);
struct tevent_req *req;
ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
- if (cli_has_async_calls(cli)) {
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
ev = tevent_context_init(talloc_tos());
state->blob_out = spnego_gen_negTokenInit(state, OIDs_ntlm, &blob_out, NULL);
data_blob_free(&blob_out);
+ 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);
+ }
+ }
+
subreq = cli_sesssetup_blob_send(state, ev, cli, state->blob_out);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
req, struct cli_session_setup_ntlmssp_state);
DATA_BLOB blob_in, msg_in, blob_out;
char *inbuf = NULL;
+ struct iovec *recv_iov = NULL;
bool parse_ret;
NTSTATUS status;
status = cli_sesssetup_blob_recv(subreq, talloc_tos(), &blob_in,
- &inbuf);
+ &inbuf, &recv_iov);
TALLOC_FREE(subreq);
data_blob_free(&state->blob_out);
cli_set_session_key(
state->cli, state->ntlmssp_state->session_key);
- if (cli_simple_set_signing(
- state->cli, state->ntlmssp_state->session_key,
- data_blob_null)
- && !cli_check_sign_mac(state->cli, inbuf, 1)) {
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
- return;
+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+ struct smbXcli_session *session = state->cli->smb2.session;
+
+ if (ntlmssp_is_anonymous(state->ntlmssp_state)) {
+ /*
+ * 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.
+ */
+ TALLOC_FREE(state->ntlmssp_state);
+ tevent_req_done(req);
+ return;
+ }
+
+ status = smb2cli_session_set_session_key(session,
+ state->ntlmssp_state->session_key,
+ recv_iov);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ } else {
+ if (smb1cli_conn_activate_signing(
+ state->cli->conn, state->ntlmssp_state->session_key,
+ data_blob_null)
+ && !smb1cli_conn_check_signing(state->cli->conn, (uint8_t *)inbuf, 1)) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
}
TALLOC_FREE(state->ntlmssp_state);
tevent_req_done(req);
struct tevent_req *req;
NTSTATUS status = NT_STATUS_NO_MEMORY;
- if (cli_has_async_calls(cli)) {
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
return NT_STATUS_INVALID_PARAMETER;
}
ev = tevent_context_init(talloc_tos());
char *account = NULL;
NTSTATUS status;
- server_blob = cli_state_server_gss_blob(cli);
+ server_blob = smbXcli_conn_server_gss_blob(cli->conn);
if (server_blob) {
blob = data_blob(server_blob->data, server_blob->length);
}
/* If password is set we reauthenticate to kerberos server
* and do not store results */
- if (cli->got_kerberos_mechanism && cli->use_kerberos) {
+ if (user && *user && cli->got_kerberos_mechanism && cli->use_kerberos) {
ADS_STATUS rc;
- const char *remote_name = cli_state_remote_name(cli);
+ const char *remote_name = smbXcli_conn_remote_name(cli->conn);
if (pass && *pass) {
int ret;
!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);
+ char *realm = strupper_talloc(talloc_tos(), dest_realm);
+ if (realm) {
+ principal = talloc_asprintf(talloc_tos(),
+ "cifs/%s@%s",
+ remote_name,
+ realm);
+ TALLOC_FREE(realm);
}
- 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();
- }
- }
-
- 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));
+ principal = kerberos_get_principal_from_service_hostname(talloc_tos(),
+ "cifs",
+ remote_name,
+ lp_realm());
}
- 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>"));
-
- SAFE_FREE(realm);
}
if (principal) {
{
char *p;
char *user2;
- uint16_t sec_mode = cli_state_security_mode(cli);
+ uint16_t sec_mode = smb1cli_conn_server_security_mode(cli->conn);
if (user) {
user2 = talloc_strdup(talloc_tos(), user);
workgroup = user2;
}
- if (cli_state_protocol(cli) < PROTOCOL_LANMAN1) {
- /*
- * Ensure cli->server_domain,
- * cli->server_os and cli->server_type
- * are valid pointers.
- */
- cli->server_domain = talloc_strdup(cli, "");
- cli->server_os = talloc_strdup(cli, "");
- cli->server_type = talloc_strdup(cli, "");
- if (cli->server_domain == NULL ||
- cli->server_os == NULL ||
- cli->server_type == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
+ if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_LANMAN1) {
return NT_STATUS_OK;
}
/* 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"));
workgroup);
}
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ 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, ("SMB2-SPNEGO login failed: %s\n", ads_errstr(status)));
+ return ads_ntstatus(status);
+ }
+ return NT_STATUS_OK;
+ }
+
/* if no user is supplied then we have to do an anonymous connection.
passwords are ignored */
/* if the server supports extended security then use SPNEGO */
- if (cli_state_capabilities(cli) & CAP_EXTENDED_SECURITY) {
+ if (smb1cli_conn_capabilities(cli->conn) & CAP_EXTENDED_SECURITY) {
const char *remote_realm = cli_state_remote_realm(cli);
ADS_STATUS status = cli_session_setup_spnego(cli, user, pass,
workgroup,
struct tevent_req *req;
NTSTATUS status = NT_STATUS_NO_MEMORY;
- if (cli_has_async_calls(cli)) {
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
return NT_STATUS_INVALID_PARAMETER;
}
ev = tevent_context_init(talloc_tos());
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);
*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 {
* 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;
}
}
- 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;
}
cli->dfsroot = false;
- if ((wct > 2) && (cli_state_protocol(cli) >= PROTOCOL_LANMAN2)) {
+ if ((wct > 2) && (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_LANMAN2)) {
cli->dfsroot = ((SVAL(vwv+2, 0) & SMB_SHARE_IN_DFS) != 0);
}
struct tevent_req *req;
NTSTATUS status = NT_STATUS_OK;
- 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
*/
return status;
}
+NTSTATUS cli_tree_connect(struct cli_state *cli, const char *share,
+ const char *dev, const char *pass, int passlen)
+{
+ cli->share = talloc_strdup(cli, share);
+ if (!cli->share) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ return smb2cli_tcon(cli, share);
+ }
+
+ return cli_tcon_andx(cli, share, dev, pass, passlen);
+}
+
/****************************************************************************
Send a tree disconnect.
****************************************************************************/
struct tevent_req *req;
NTSTATUS status = NT_STATUS_NO_MEMORY;
- if (cli_has_async_calls(cli)) {
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
return NT_STATUS_INVALID_PARAMETER;
}
ev = tevent_context_init(talloc_tos());
return status;
}
-/****************************************************************************
- Send a negprot command.
-****************************************************************************/
-
-struct cli_negprot_state {
- struct cli_state *cli;
- enum protocol_types max_protocol;
-};
-
-static void cli_negprot_done(struct tevent_req *subreq);
-
-struct tevent_req *cli_negprot_send(TALLOC_CTX *mem_ctx,
- struct event_context *ev,
- struct cli_state *cli,
- enum protocol_types max_protocol)
-{
- struct tevent_req *req, *subreq;
- struct cli_negprot_state *state;
- uint8_t *bytes = NULL;
- int numprots;
- enum protocol_types tmp_protocol;
-
- req = tevent_req_create(mem_ctx, &state, struct cli_negprot_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;
- }
- bytes = (uint8_t *)talloc_append_blob(
- state, bytes, data_blob_const(&c, sizeof(c)));
- if (tevent_req_nomem(bytes, req)) {
- return tevent_req_post(req, ev);
- }
- bytes = smb_bytes_push_str(bytes, false,
- prots[numprots].name,
- strlen(prots[numprots].name)+1,
- NULL);
- if (tevent_req_nomem(bytes, req)) {
- return tevent_req_post(req, ev);
- }
- }
-
- 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;
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq, cli_negprot_done, req);
- return req;
-}
-
-static void cli_negprot_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct cli_negprot_state *state = tevent_req_data(
- req, struct cli_negprot_state);
- struct cli_state *cli = state->cli;
- uint8_t flags;
- uint8_t wct;
- uint16_t *vwv;
- uint32_t num_bytes;
- uint8_t *bytes;
- 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);
- return;
- }
-
- 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;
- }
-
- if (flags & FLAG_SUPPORT_LOCKREAD) {
- server_lockread = true;
- server_writeunlock = true;
- }
-
- 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;
-
- 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);
- 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;
- }
- }
-
- 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;
- }
- }
- }
-
- 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;
- }
- }
- } 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;
- }
-
- if (server_max_xmit < 1024) {
- tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- if (server_max_mux < 1) {
- tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- 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;
- }
- }
-
- 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)
-{
- return tevent_req_simple_recv_ntstatus(req);
-}
-
-NTSTATUS cli_negprot(struct cli_state *cli, enum protocol_types max_protocol)
-{
- TALLOC_CTX *frame = talloc_stackframe();
- struct event_context *ev;
- struct tevent_req *req;
- NTSTATUS status = NT_STATUS_OK;
-
- if (cli_has_async_calls(cli)) {
- /*
- * Can't use sync call while an async call is in flight
- */
- status = NT_STATUS_INVALID_PARAMETER;
- goto fail;
- }
-
- ev = event_context_init(frame);
- if (ev == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
-
- req = cli_negprot_send(frame, ev, cli, max_protocol);
- if (req == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
-
- if (!tevent_req_poll(req, ev)) {
- status = map_nt_error_from_unix(errno);
- goto fail;
- }
-
- status = cli_negprot_recv(req);
- fail:
- TALLOC_FREE(frame);
- return status;
-}
-
static NTSTATUS cli_connect_sock(const char *host, int name_type,
const struct sockaddr_storage *pss,
const char *myname, uint16_t port,
cli = cli_state_create(NULL, fd, desthost, NULL, signing_state, flags);
if (cli == NULL) {
+ close(fd);
+ fd = -1;
goto fail;
}
return nt_status;
}
- nt_status = cli_negprot(cli, PROTOCOL_NT1);
+ nt_status = smbXcli_negprot(cli->conn, cli->timeout, PROTOCOL_CORE,
+ PROTOCOL_NT1);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(1, ("failed negprot: %s\n", nt_errstr(nt_status)));
cli_shutdown(cli);
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++) {