#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 "libsmb/nmblib.h"
#include "librpc/ndr/libndr.h"
#include "../libcli/smb/smbXcli_base.h"
-#include "smb2cli.h"
#define STAR_SMBSERVER "*SMBSERVER"
return NT_STATUS_OK;
}
-/****************************************************************************
- Do an old lanman2 style session setup.
-****************************************************************************/
-
-struct cli_session_setup_lanman2_state {
- struct cli_state *cli;
- uint16_t vwv[10];
- const char *user;
-};
-
-static void cli_session_setup_lanman2_done(struct tevent_req *subreq);
-
-static struct tevent_req *cli_session_setup_lanman2_send(
- TALLOC_CTX *mem_ctx, struct tevent_context *ev,
- struct cli_state *cli, const char *user,
- const char *pass, size_t passlen,
- const char *workgroup)
-{
- struct tevent_req *req, *subreq;
- struct cli_session_setup_lanman2_state *state;
- DATA_BLOB lm_response = data_blob_null;
- uint16_t *vwv;
- uint8_t *bytes;
- char *tmp;
- uint16_t sec_mode = smb1cli_conn_server_security_mode(cli->conn);
-
- req = tevent_req_create(mem_ctx, &state,
- struct cli_session_setup_lanman2_state);
- if (req == NULL) {
- return NULL;
- }
- state->cli = cli;
- state->user = user;
- vwv = state->vwv;
-
- /*
- * if in share level security then don't send a password now
- */
- if (!(sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) {
- passlen = 0;
- }
-
- if (passlen > 0
- && (sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)
- && passlen != 24) {
- /*
- * Encrypted mode needed, and non encrypted password
- * supplied.
- */
- lm_response = data_blob(NULL, 24);
- if (tevent_req_nomem(lm_response.data, req)) {
- return tevent_req_post(req, ev);
- }
-
- 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 "
- "authentication\n"));
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
- return tevent_req_post(req, ev);
- }
- } else if ((sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)
- && passlen == 24) {
- /*
- * Encrypted mode needed, and encrypted password
- * supplied.
- */
- lm_response = data_blob(pass, passlen);
- if (tevent_req_nomem(lm_response.data, req)) {
- return tevent_req_post(req, ev);
- }
- } else if (passlen > 0) {
- uint8_t *buf;
- size_t converted_size;
- /*
- * Plaintext mode needed, assume plaintext supplied.
- */
- buf = talloc_array(talloc_tos(), uint8_t, 0);
- 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);
- }
- lm_response = data_blob(pass, passlen);
- TALLOC_FREE(buf);
- if (tevent_req_nomem(lm_response.data, req)) {
- return tevent_req_post(req, ev);
- }
- }
-
- SCVAL(vwv+0, 0, 0xff);
- SCVAL(vwv+0, 1, 0);
- SSVAL(vwv+1, 0, 0);
- SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
- SSVAL(vwv+3, 0, 2);
- SSVAL(vwv+4, 0, 1);
- 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(bytes, req)) {
- return tevent_req_post(req, ev);
- }
- if (lm_response.length != 0) {
- memcpy(bytes, lm_response.data, lm_response.length);
- }
- data_blob_free(&lm_response);
-
- tmp = talloc_strdup_upper(talloc_tos(), user);
- if (tevent_req_nomem(tmp, req)) {
- return tevent_req_post(req, ev);
- }
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), tmp, strlen(tmp)+1,
- NULL);
- TALLOC_FREE(tmp);
-
- tmp = talloc_strdup_upper(talloc_tos(), workgroup);
- if (tevent_req_nomem(tmp, req)) {
- return tevent_req_post(req, ev);
- }
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), tmp, strlen(tmp)+1,
- 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);
- }
-
- subreq = cli_smb_send(state, ev, cli, SMBsesssetupX, 0, 10, vwv,
- talloc_get_size(bytes), bytes);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq, cli_session_setup_lanman2_done, req);
- return req;
-}
-
-static void cli_session_setup_lanman2_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct cli_session_setup_lanman2_state *state = tevent_req_data(
- req, struct cli_session_setup_lanman2_state);
- struct cli_state *cli = state->cli;
- uint32_t num_bytes;
- uint8_t *in;
- uint8_t *inhdr;
- uint8_t *bytes;
- uint8_t *p;
- NTSTATUS status;
- ssize_t ret;
- uint8_t wct;
- uint16_t *vwv;
-
- status = cli_smb_recv(subreq, state, &in, 3, &wct, &vwv,
- &num_bytes, &bytes);
- TALLOC_FREE(subreq);
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
- }
-
- inhdr = in + NBT_HDR_SIZE;
- p = bytes;
-
- cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
-
- status = smb_bytes_talloc_string(cli,
- inhdr,
- &cli->server_os,
- p,
- bytes+num_bytes-p,
- &ret);
-
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
- }
- p += ret;
-
- status = smb_bytes_talloc_string(cli,
- inhdr,
- &cli->server_type,
- p,
- bytes+num_bytes-p,
- &ret);
-
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
- }
- p += ret;
-
- status = smb_bytes_talloc_string(cli,
- inhdr,
- &cli->server_domain,
- p,
- bytes+num_bytes-p,
- &ret);
-
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
- }
- p += ret;
-
- status = cli_set_username(cli, state->user);
- if (tevent_req_nterror(req, status)) {
- return;
- }
- tevent_req_done(req);
-}
-
-static NTSTATUS cli_session_setup_lanman2_recv(struct tevent_req *req)
-{
- return tevent_req_simple_recv_ntstatus(req);
-}
-
/****************************************************************************
Work out suitable capabilities to offer the server.
****************************************************************************/
state->bytes.iov_base = (void *)bytes;
state->bytes.iov_len = talloc_get_size(bytes);
- subreq = cli_smb_req_create(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
- 1, &state->bytes);
+ subreq = cli_smb_req_create(state, ev, cli, SMBsesssetupX, 0, 0, 13,
+ vwv, 1, &state->bytes);
if (subreq == NULL) {
TALLOC_FREE(req);
return NULL;
p = bytes;
cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
+ smb1cli_session_set_action(cli->smb1.session, SVAL(vwv+2, 0));
status = smb_bytes_talloc_string(cli,
inhdr,
}
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);
}
-/****************************************************************************
- Do a NT1 plaintext session setup.
-****************************************************************************/
+/* The following is calculated from :
+ * (smb_size-4) = 35
+ * (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() )
+ * (strlen("Unix") + 1 + strlen("Samba") + 1) * 2 = 22 (unicode strings at
+ * end of packet.
+ */
+
+#define BASE_SESSSETUP_BLOB_PACKET_SIZE (35 + 24 + 22)
-struct cli_session_setup_plain_state {
+struct cli_sesssetup_blob_state {
+ struct tevent_context *ev;
struct cli_state *cli;
- uint16_t vwv[13];
- const char *user;
+ DATA_BLOB blob;
+ uint16_t max_blob_size;
+
+ DATA_BLOB this_blob;
+ struct iovec *recv_iov;
+
+ NTSTATUS status;
+ const uint8_t *inbuf;
+ DATA_BLOB ret_blob;
+
+ char *out_native_os;
+ char *out_native_lm;
};
-static void cli_session_setup_plain_done(struct tevent_req *subreq);
+static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
+ struct tevent_req **psubreq);
+static void cli_sesssetup_blob_done(struct tevent_req *subreq);
-static struct tevent_req *cli_session_setup_plain_send(
- TALLOC_CTX *mem_ctx, struct tevent_context *ev,
- struct cli_state *cli,
- const char *user, const char *pass, const char *workgroup)
+static struct tevent_req *cli_sesssetup_blob_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ DATA_BLOB blob)
{
struct tevent_req *req, *subreq;
- struct cli_session_setup_plain_state *state;
- uint16_t *vwv;
- uint8_t *bytes;
- size_t passlen;
- char *version;
+ struct cli_sesssetup_blob_state *state;
+ uint32_t usable_space;
req = tevent_req_create(mem_ctx, &state,
- struct cli_session_setup_plain_state);
+ struct cli_sesssetup_blob_state);
if (req == NULL) {
return NULL;
}
+ state->ev = ev;
+ state->blob = blob;
state->cli = cli;
- state->user = user;
- vwv = state->vwv;
-
- SCVAL(vwv+0, 0, 0xff);
- SCVAL(vwv+0, 1, 0);
- SSVAL(vwv+1, 0, 0);
- SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
- SSVAL(vwv+3, 0, 2);
- SSVAL(vwv+4, 0, cli_state_get_vc_num(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);
- SSVAL(vwv+10, 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, 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 + (smbXcli_conn_use_unicode(cli->conn) ? 8 : 7), 0, passlen);
-
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
- user, strlen(user)+1, NULL);
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
- workgroup, strlen(workgroup)+1, NULL);
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
- "Unix", 5, NULL);
- version = talloc_asprintf(talloc_tos(), "Samba %s",
- samba_version_string());
- if (tevent_req_nomem(version, req)){
- return tevent_req_post(req, ev);
+ 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);
}
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
- version, strlen(version)+1, NULL);
- TALLOC_FREE(version);
- if (tevent_req_nomem(bytes, req)) {
+ if (usable_space == 0) {
+ DEBUG(1, ("cli_session_setup_blob: cli->max_xmit too small "
+ "(not possible to send %u bytes)\n",
+ BASE_SESSSETUP_BLOB_PACKET_SIZE + 1));
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
return tevent_req_post(req, ev);
}
+ state->max_blob_size = MIN(usable_space, 0xFFFF);
- subreq = cli_smb_send(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
- talloc_get_size(bytes), bytes);
- if (tevent_req_nomem(subreq, req)) {
+ if (!cli_sesssetup_blob_next(state, &subreq)) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
return tevent_req_post(req, ev);
}
- tevent_req_set_callback(subreq, cli_session_setup_plain_done, req);
+ tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
return req;
}
-static void cli_session_setup_plain_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct cli_session_setup_plain_state *state = tevent_req_data(
- req, struct cli_session_setup_plain_state);
- struct cli_state *cli = state->cli;
- uint32_t num_bytes;
- uint8_t *in;
- uint8_t *inhdr;
- uint8_t *bytes;
- uint8_t *p;
- NTSTATUS status;
- ssize_t ret;
- uint8_t wct;
- uint16_t *vwv;
-
- status = cli_smb_recv(subreq, state, &in, 3, &wct, &vwv,
- &num_bytes, &bytes);
- TALLOC_FREE(subreq);
- if (tevent_req_nterror(req, status)) {
- return;
- }
-
- inhdr = in + NBT_HDR_SIZE;
- p = bytes;
-
- cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
-
- status = smb_bytes_talloc_string(cli,
- inhdr,
- &cli->server_os,
- p,
- bytes+num_bytes-p,
- &ret);
-
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
- }
- p += ret;
-
- status = smb_bytes_talloc_string(cli,
- inhdr,
- &cli->server_type,
- p,
- bytes+num_bytes-p,
- &ret);
-
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
- }
- p += ret;
-
- status = smb_bytes_talloc_string(cli,
- inhdr,
- &cli->server_domain,
- p,
- bytes+num_bytes-p,
- &ret);
-
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
- }
- p += ret;
-
- status = cli_set_username(cli, state->user);
- if (tevent_req_nterror(req, status)) {
- return;
- }
-
- tevent_req_done(req);
-}
-
-static NTSTATUS cli_session_setup_plain_recv(struct tevent_req *req)
-{
- return tevent_req_simple_recv_ntstatus(req);
-}
-
-/****************************************************************************
- do a NT1 NTLM/LM encrypted session setup - for when extended security
- is not negotiated.
- @param cli client state to create do session setup on
- @param user username
- @param pass *either* cleartext password (passlen !=24) or LM response.
- @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
- @param workgroup The user's domain.
-****************************************************************************/
-
-struct cli_session_setup_nt1_state {
- struct cli_state *cli;
- uint16_t vwv[13];
- DATA_BLOB response;
- DATA_BLOB session_key;
- const char *user;
-};
-
-static void cli_session_setup_nt1_done(struct tevent_req *subreq);
-
-static struct tevent_req *cli_session_setup_nt1_send(
- TALLOC_CTX *mem_ctx, struct tevent_context *ev,
- struct cli_state *cli, const char *user,
- const char *pass, size_t passlen,
- const char *ntpass, size_t ntpasslen,
- const char *workgroup)
-{
- struct tevent_req *req, *subreq;
- struct cli_session_setup_nt1_state *state;
- DATA_BLOB lm_response = data_blob_null;
- DATA_BLOB nt_response = data_blob_null;
- DATA_BLOB session_key = data_blob_null;
- uint16_t *vwv;
- uint8_t *bytes;
- char *workgroup_upper;
-
- req = tevent_req_create(mem_ctx, &state,
- struct cli_session_setup_nt1_state);
- if (req == NULL) {
- return NULL;
- }
- state->cli = cli;
- state->user = user;
- vwv = state->vwv;
-
- if (passlen == 0) {
- /* do nothing - guest login */
- } else if (passlen != 24) {
- if (lp_client_ntlmv2_auth()) {
- DATA_BLOB server_chal;
- DATA_BLOB names_blob;
-
- server_chal =
- data_blob_const(smb1cli_conn_server_challenge(cli->conn),
- 8);
-
- /*
- * note that the 'workgroup' here is a best
- * guess - we don't know the server's domain
- * at this point. Windows clients also don't
- * use hostname...
- */
- names_blob = NTLMv2_generate_names_blob(
- NULL, NULL, workgroup);
-
- if (tevent_req_nomem(names_blob.data, req)) {
- return tevent_req_post(req, ev);
- }
-
- if (!SMBNTLMv2encrypt(NULL, user, workgroup, pass,
- &server_chal, &names_blob,
- &lm_response, &nt_response,
- NULL, &session_key)) {
- data_blob_free(&names_blob);
- tevent_req_nterror(
- req, NT_STATUS_ACCESS_DENIED);
- return tevent_req_post(req, ev);
- }
- data_blob_free(&names_blob);
-
- } else {
- uchar nt_hash[16];
- E_md4hash(pass, nt_hash);
-
-#ifdef LANMAN_ONLY
- nt_response = data_blob_null;
-#else
- nt_response = data_blob(NULL, 24);
- if (tevent_req_nomem(nt_response.data, req)) {
- return tevent_req_post(req, ev);
- }
-
- SMBNTencrypt(pass, smb1cli_conn_server_challenge(cli->conn),
- nt_response.data);
-#endif
- /* non encrypted password supplied. Ignore ntpass. */
- if (lp_client_lanman_auth()) {
-
- lm_response = data_blob(NULL, 24);
- if (tevent_req_nomem(lm_response.data, req)) {
- return tevent_req_post(req, ev);
- }
-
- if (!SMBencrypt(pass,
- smb1cli_conn_server_challenge(cli->conn),
- lm_response.data)) {
- /*
- * Oops, the LM response is
- * invalid, just put the NT
- * response there instead
- */
- data_blob_free(&lm_response);
- lm_response = data_blob(
- nt_response.data,
- nt_response.length);
- }
- } else {
- /*
- * LM disabled, place NT# in LM field
- * instead
- */
- lm_response = data_blob(
- nt_response.data, nt_response.length);
- }
-
- if (tevent_req_nomem(lm_response.data, req)) {
- return tevent_req_post(req, ev);
- }
-
- session_key = data_blob(NULL, 16);
- if (tevent_req_nomem(session_key.data, req)) {
- return tevent_req_post(req, ev);
- }
-#ifdef LANMAN_ONLY
- E_deshash(pass, session_key.data);
- memset(&session_key.data[8], '\0', 8);
-#else
- SMBsesskeygen_ntv1(nt_hash, session_key.data);
-#endif
- }
- } else {
- /* pre-encrypted password supplied. Only used for
- security=server, can't do
- signing because we don't have original key */
-
- lm_response = data_blob(pass, passlen);
- if (tevent_req_nomem(lm_response.data, req)) {
- return tevent_req_post(req, ev);
- }
-
- nt_response = data_blob(ntpass, ntpasslen);
- if (tevent_req_nomem(nt_response.data, req)) {
- return tevent_req_post(req, ev);
- }
- }
-
-#ifdef LANMAN_ONLY
- state->response = data_blob_talloc(
- state, lm_response.data, lm_response.length);
-#else
- state->response = data_blob_talloc(
- state, nt_response.data, nt_response.length);
-#endif
- if (tevent_req_nomem(state->response.data, req)) {
- return tevent_req_post(req, ev);
- }
-
- if (session_key.data) {
- state->session_key = data_blob_talloc(
- state, session_key.data, session_key.length);
- if (tevent_req_nomem(state->session_key.data, req)) {
- return tevent_req_post(req, ev);
- }
- }
- data_blob_free(&session_key);
-
- SCVAL(vwv+0, 0, 0xff);
- SCVAL(vwv+0, 1, 0);
- SSVAL(vwv+1, 0, 0);
- SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
- SSVAL(vwv+3, 0, 2);
- SSVAL(vwv+4, 0, cli_state_get_vc_num(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);
- SSVAL(vwv+10, 0, 0);
- SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli, 0));
-
- bytes = talloc_array(state, uint8_t,
- lm_response.length + nt_response.length);
- if (tevent_req_nomem(bytes, req)) {
- return tevent_req_post(req, ev);
- }
- if (lm_response.length != 0) {
- memcpy(bytes, lm_response.data, lm_response.length);
- }
- if (nt_response.length != 0) {
- memcpy(bytes + lm_response.length,
- nt_response.data, nt_response.length);
- }
- data_blob_free(&lm_response);
- data_blob_free(&nt_response);
-
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
- user, strlen(user)+1, NULL);
-
- /*
- * Upper case here might help some NTLMv2 implementations
- */
- workgroup_upper = talloc_strdup_upper(talloc_tos(), workgroup);
- if (tevent_req_nomem(workgroup_upper, req)) {
- return tevent_req_post(req, ev);
- }
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
- workgroup_upper, strlen(workgroup_upper)+1,
- NULL);
- TALLOC_FREE(workgroup_upper);
-
- 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);
- }
-
- subreq = cli_smb_send(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
- talloc_get_size(bytes), bytes);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq, cli_session_setup_nt1_done, req);
- return req;
-}
-
-static void cli_session_setup_nt1_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct cli_session_setup_nt1_state *state = tevent_req_data(
- req, struct cli_session_setup_nt1_state);
- struct cli_state *cli = state->cli;
- uint32_t num_bytes;
- uint8_t *in;
- uint8_t *inhdr;
- uint8_t *bytes;
- uint8_t *p;
- NTSTATUS status;
- ssize_t ret;
- uint8_t wct;
- uint16_t *vwv;
-
- status = cli_smb_recv(subreq, state, &in, 3, &wct, &vwv,
- &num_bytes, &bytes);
- TALLOC_FREE(subreq);
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
- }
-
- inhdr = in + NBT_HDR_SIZE;
- p = bytes;
-
- cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
-
- status = smb_bytes_talloc_string(cli,
- inhdr,
- &cli->server_os,
- p,
- bytes+num_bytes-p,
- &ret);
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
- }
- p += ret;
-
- status = smb_bytes_talloc_string(cli,
- inhdr,
- &cli->server_type,
- p,
- bytes+num_bytes-p,
- &ret);
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
- }
- p += ret;
-
- status = smb_bytes_talloc_string(cli,
- inhdr,
- &cli->server_domain,
- p,
- bytes+num_bytes-p,
- &ret);
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
- }
- p += ret;
-
- status = cli_set_username(cli, state->user);
- if (tevent_req_nterror(req, status)) {
- return;
- }
- 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) {
- 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);
-}
-
-static NTSTATUS cli_session_setup_nt1_recv(struct tevent_req *req)
-{
- return tevent_req_simple_recv_ntstatus(req);
-}
-
-/* The following is calculated from :
- * (smb_size-4) = 35
- * (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() )
- * (strlen("Unix") + 1 + strlen("Samba") + 1) * 2 = 22 (unicode strings at
- * end of packet.
- */
-
-#define BASE_SESSSETUP_BLOB_PACKET_SIZE (35 + 24 + 22)
-
-struct cli_sesssetup_blob_state {
- struct tevent_context *ev;
- struct cli_state *cli;
- DATA_BLOB blob;
- uint16_t max_blob_size;
- uint16_t vwv[12];
- uint8_t *buf;
-
- DATA_BLOB smb2_blob;
- struct iovec *recv_iov;
-
- NTSTATUS status;
- uint8_t *inbuf;
- DATA_BLOB ret_blob;
-};
-
-static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
- struct tevent_req **psubreq);
-static void cli_sesssetup_blob_done(struct tevent_req *subreq);
-
-static struct tevent_req *cli_sesssetup_blob_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct cli_state *cli,
- DATA_BLOB blob)
-{
- struct tevent_req *req, *subreq;
- struct cli_sesssetup_blob_state *state;
- uint32_t usable_space;
-
- req = tevent_req_create(mem_ctx, &state,
- struct cli_sesssetup_blob_state);
- if (req == NULL) {
- return NULL;
- }
- state->ev = ev;
- state->blob = blob;
- state->cli = cli;
-
- 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 "
- "(not possible to send %u bytes)\n",
- BASE_SESSSETUP_BLOB_PACKET_SIZE + 1));
- tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
- return tevent_req_post(req, ev);
- }
- state->max_blob_size = MIN(usable_space, 0xFFFF);
-
- if (!cli_sesssetup_blob_next(state, &subreq)) {
- tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
- return req;
-}
-
-static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
- struct tevent_req **psubreq)
+static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
+ struct tevent_req **psubreq)
{
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->this_blob.data = state->blob.data;
+ state->this_blob.length = thistime;
- state->blob.data += thistime;
- state->blob.length -= thistime;
+ state->blob.data += thistime;
+ state->blob.length -= thistime;
+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
subreq = smb2cli_session_setup_send(state, state->ev,
state->cli->conn,
state->cli->timeout,
SMB2_CAP_DFS, /* in_capabilities */
0, /* in_channel */
0, /* in_previous_session_id */
- &state->smb2_blob);
+ &state->this_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+2, 0, CLI_BUFFER_SIZE);
- SSVAL(state->vwv+3, 0, 2);
- SSVAL(state->vwv+4, 0, 1);
- SIVAL(state->vwv+5, 0, 0);
-
- SSVAL(state->vwv+7, 0, thistime);
-
- SSVAL(state->vwv+8, 0, 0);
- SSVAL(state->vwv+9, 0, 0);
- SIVAL(state->vwv+10, 0,
- cli_session_setup_capabilities(state->cli, CAP_EXTENDED_SECURITY));
-
- state->buf = (uint8_t *)talloc_memdup(state, state->blob.data,
- thistime);
- if (state->buf == NULL) {
- return false;
- }
- state->blob.data += thistime;
- state->blob.length -= thistime;
+ } else {
+ uint16_t in_buf_size = 0;
+ uint16_t in_mpx_max = 0;
+ uint16_t in_vc_num = 0;
+ uint32_t in_sess_key = 0;
+ uint32_t in_capabilities = 0;
+ const char *in_native_os = NULL;
+ const char *in_native_lm = NULL;
+
+ in_buf_size = CLI_BUFFER_SIZE;
+ in_mpx_max = smbXcli_conn_max_requests(state->cli->conn);
+ in_vc_num = cli_state_get_vc_num(state->cli);
+ in_sess_key = smb1cli_conn_server_session_key(state->cli->conn);
+ in_capabilities = cli_session_setup_capabilities(state->cli,
+ CAP_EXTENDED_SECURITY);
+ in_native_os = "Unix";
+ in_native_lm = "Samba";
- 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, smbXcli_conn_use_unicode(state->cli->conn),
- "Samba", 6, NULL);
- if (state->buf == NULL) {
- return false;
- }
- subreq = cli_smb_send(state, state->ev, state->cli, SMBsesssetupX, 0,
- 12, state->vwv,
- talloc_get_size(state->buf), state->buf);
- if (subreq == NULL) {
- return false;
+ /*
+ * For now we keep the same values as before,
+ * we may remove these in a separate commit later.
+ */
+ in_mpx_max = 2;
+ in_vc_num = 1;
+ in_sess_key = 0;
+
+ subreq = smb1cli_session_setup_ext_send(state, state->ev,
+ state->cli->conn,
+ state->cli->timeout,
+ state->cli->smb1.pid,
+ state->cli->smb1.session,
+ in_buf_size,
+ in_mpx_max,
+ in_vc_num,
+ in_sess_key,
+ state->this_blob,
+ in_capabilities,
+ in_native_os,
+ in_native_lm);
+ if (subreq == NULL) {
+ return false;
+ }
}
*psubreq = subreq;
return true;
struct cli_sesssetup_blob_state *state = tevent_req_data(
req, struct cli_sesssetup_blob_state);
struct cli_state *cli = state->cli;
- uint8_t wct;
- uint16_t *vwv;
- uint32_t num_bytes;
- uint8_t *bytes;
NTSTATUS status;
- uint8_t *p;
- uint16_t blob_length;
- uint8_t *in;
- uint8_t *inhdr;
- ssize_t ret;
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);
+ status = smb1cli_session_setup_ext_recv(subreq, state,
+ &state->recv_iov,
+ &state->inbuf,
+ &state->ret_blob,
+ &state->out_native_os,
+ &state->out_native_lm);
}
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)
return;
}
- state->status = status;
-
- 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) {
- tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
- state->ret_blob = data_blob_const(bytes, blob_length);
-
- p = bytes + blob_length;
-
- status = smb_bytes_talloc_string(cli,
- inhdr,
- &cli->server_os,
- p,
- bytes+num_bytes-p,
- &ret);
-
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
+ if (cli->server_os == NULL) {
+ cli->server_os = talloc_move(cli, &state->out_native_os);
}
- p += ret;
-
- status = smb_bytes_talloc_string(cli,
- inhdr,
- &cli->server_type,
- p,
- bytes+num_bytes-p,
- &ret);
-
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
+ if (cli->server_type == NULL) {
+ cli->server_type = talloc_move(cli, &state->out_native_lm);
}
- p += ret;
-
- status = smb_bytes_talloc_string(cli,
- inhdr,
- &cli->server_domain,
- p,
- bytes+num_bytes-p,
- &ret);
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
- }
- p += ret;
+ state->status = status;
-next:
if (state->blob.length != 0) {
/*
* More to send
return;
}
tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
- return;
- }
- tevent_req_done(req);
-}
-
-static NTSTATUS cli_sesssetup_blob_recv(struct tevent_req *req,
- TALLOC_CTX *mem_ctx,
- DATA_BLOB *pblob,
- uint8_t **pinbuf,
- struct iovec **precv_iov)
-{
- struct cli_sesssetup_blob_state *state = tevent_req_data(
- req, struct cli_sesssetup_blob_state);
- NTSTATUS status;
- 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;
-}
-
-#ifdef HAVE_KRB5
-
-/****************************************************************************
- Use in-memory credentials cache
-****************************************************************************/
-
-static void use_in_memory_ccache(void) {
- setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
-}
-
-/****************************************************************************
- Do a spnego/kerberos encrypted session setup.
-****************************************************************************/
-
-struct cli_session_setup_kerberos_state {
- struct cli_state *cli;
- DATA_BLOB negTokenTarg;
- DATA_BLOB session_key_krb5;
- ADS_STATUS ads_status;
-};
-
-static void cli_session_setup_kerberos_done(struct tevent_req *subreq);
-
-static struct tevent_req *cli_session_setup_kerberos_send(
- TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
- const char *principal)
-{
- struct tevent_req *req, *subreq;
- struct cli_session_setup_kerberos_state *state;
- int rc;
-
- DEBUG(2,("Doing kerberos session setup\n"));
-
- req = tevent_req_create(mem_ctx, &state,
- struct cli_session_setup_kerberos_state);
- if (req == NULL) {
- return NULL;
- }
- state->cli = cli;
- state->ads_status = ADS_SUCCESS;
-
- /*
- * 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, 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);
- return tevent_req_post(req, ev);
- }
-
-#if 0
- file_save("negTokenTarg.dat", state->negTokenTarg.data,
- 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);
- }
- tevent_req_set_callback(subreq, cli_session_setup_kerberos_done, req);
- return req;
-}
-
-static void cli_session_setup_kerberos_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct cli_session_setup_kerberos_state *state = tevent_req_data(
- req, struct cli_session_setup_kerberos_state);
- uint8_t *inbuf = NULL;
- struct iovec *recv_iov = NULL;
- NTSTATUS status;
-
- 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);
- 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 {
- struct smbXcli_session *session = state->cli->smb1.session;
-
- status = smb1cli_session_set_session_key(session,
- state->session_key_krb5);
- if (tevent_req_nterror(req, status)) {
- return;
- }
-
- if (smb1cli_conn_activate_signing(state->cli->conn, state->session_key_krb5,
- data_blob_null)
- && !smb1cli_conn_check_signing(state->cli->conn, inbuf, 1)) {
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
- return;
- }
+ return;
}
-
tevent_req_done(req);
}
-static ADS_STATUS cli_session_setup_kerberos_recv(struct tevent_req *req)
+static NTSTATUS cli_sesssetup_blob_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *pblob,
+ const uint8_t **pinbuf,
+ struct iovec **precv_iov)
{
- struct cli_session_setup_kerberos_state *state = tevent_req_data(
- req, struct cli_session_setup_kerberos_state);
+ struct cli_sesssetup_blob_state *state = tevent_req_data(
+ req, struct cli_sesssetup_blob_state);
NTSTATUS status;
+ struct iovec *recv_iov;
if (tevent_req_is_nterror(req, &status)) {
- return ADS_ERROR_NT(status);
+ TALLOC_FREE(state->cli->smb2.session);
+ cli_state_set_uid(state->cli, UID_FIELD_INVALID);
+ tevent_req_received(req);
+ return status;
+ }
+
+ recv_iov = talloc_move(mem_ctx, &state->recv_iov);
+ if (pblob != NULL) {
+ *pblob = state->ret_blob;
+ }
+ if (pinbuf != NULL) {
+ *pinbuf = state->inbuf;
+ }
+ if (precv_iov != NULL) {
+ *precv_iov = recv_iov;
}
- return state->ads_status;
+ /* could be NT_STATUS_MORE_PROCESSING_REQUIRED */
+ status = state->status;
+ tevent_req_received(req);
+ return status;
}
-#endif /* HAVE_KRB5 */
+/****************************************************************************
+ Use in-memory credentials cache
+****************************************************************************/
+
+static void use_in_memory_ccache(void) {
+ setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
+}
/****************************************************************************
Do a spnego/NTLMSSP encrypted session setup.
****************************************************************************/
-struct cli_session_setup_ntlmssp_state {
+struct cli_session_setup_gensec_state {
struct tevent_context *ev;
struct cli_state *cli;
- struct ntlmssp_state *ntlmssp_state;
- int turn;
+ struct auth_generic_state *auth_generic;
+ bool is_anonymous;
+ DATA_BLOB blob_in;
+ const uint8_t *inbuf;
+ struct iovec *recv_iov;
DATA_BLOB blob_out;
+ bool local_ready;
+ bool remote_ready;
+ DATA_BLOB session_key;
};
-static int cli_session_setup_ntlmssp_state_destructor(
- struct cli_session_setup_ntlmssp_state *state)
+static int cli_session_setup_gensec_state_destructor(
+ struct cli_session_setup_gensec_state *state)
{
- if (state->ntlmssp_state != NULL) {
- TALLOC_FREE(state->ntlmssp_state);
- }
+ TALLOC_FREE(state->auth_generic);
+ data_blob_clear_free(&state->session_key);
return 0;
}
-static void cli_session_setup_ntlmssp_done(struct tevent_req *req);
+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_ntlmssp_send(
+static struct tevent_req *cli_session_setup_gensec_send(
TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
- const char *user, const char *pass, const char *domain)
+ const char *user, const char *pass, const char *domain,
+ enum credentials_use_kerberos krb5_state,
+ const char *target_service,
+ const char *target_hostname)
{
- struct tevent_req *req, *subreq;
- struct cli_session_setup_ntlmssp_state *state;
+ struct tevent_req *req;
+ struct cli_session_setup_gensec_state *state;
NTSTATUS status;
- DATA_BLOB blob_out;
- const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
+ const DATA_BLOB *b = NULL;
req = tevent_req_create(mem_ctx, &state,
- struct cli_session_setup_ntlmssp_state);
+ struct cli_session_setup_gensec_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);
+ state, cli_session_setup_gensec_state_destructor);
- 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;
+ if (user == NULL || strlen(user) == 0) {
+ if (pass != NULL && strlen(pass) == 0) {
+ /*
+ * some callers pass "" as no password
+ *
+ * gensec only handles NULL as no password.
+ */
+ pass = NULL;
+ }
+ }
+
+ status = auth_generic_client_prepare(state, &state->auth_generic);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
}
- ntlmssp_want_feature(state->ntlmssp_state,
- NTLMSSP_FEATURE_SESSION_KEY);
+
+ gensec_want_feature(state->auth_generic->gensec_security,
+ GENSEC_FEATURE_SESSION_KEY);
if (cli->use_ccache) {
- ntlmssp_want_feature(state->ntlmssp_state,
- NTLMSSP_FEATURE_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;
+ }
}
- status = ntlmssp_set_username(state->ntlmssp_state, user);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
+
+ status = auth_generic_set_username(state->auth_generic, user);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
}
- status = ntlmssp_set_domain(state->ntlmssp_state, domain);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
+
+ 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) {
- status = ntlmssp_set_password_hash(state->ntlmssp_state, pass);
+ 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 = ntlmssp_set_password(state->ntlmssp_state, pass);
+ status = auth_generic_set_password(state->auth_generic, pass);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
}
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
+
+ cli_credentials_set_kerberos_state(state->auth_generic->credentials,
+ krb5_state);
+
+ 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);
+ }
}
- status = ntlmssp_update(state->ntlmssp_state, data_blob_null,
- &blob_out);
- if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- goto fail;
+
+ 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);
+ }
+ }
+
+ b = smbXcli_conn_server_gss_blob(cli->conn);
+ if (b != NULL) {
+ state->blob_in = *b;
}
- state->blob_out = spnego_gen_negTokenInit(state, OIDs_ntlm, &blob_out, NULL);
- data_blob_free(&blob_out);
+ 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,
}
}
- subreq = cli_sesssetup_blob_send(state, ev, cli, state->blob_out);
- if (tevent_req_nomem(subreq, req)) {
+ 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_ntlmssp_done, req);
+
return req;
-fail:
- tevent_req_nterror(req, status);
- return tevent_req_post(req, ev);
}
-static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq)
+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_ntlmssp_state *state = tevent_req_data(
- req, struct cli_session_setup_ntlmssp_state);
- DATA_BLOB blob_in, msg_in, blob_out;
- uint8_t *inbuf = NULL;
- struct iovec *recv_iov = NULL;
- bool parse_ret;
+ 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(), &blob_in,
- &inbuf, &recv_iov);
+ status = gensec_update_recv(subreq, state, &state->blob_out);
TALLOC_FREE(subreq);
- data_blob_free(&state->blob_out);
+ 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;
+ }
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;
- }
- }
+ state->local_ready = true;
+ }
- 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;
- }
+ if (state->local_ready && state->remote_ready) {
+ cli_session_setup_gensec_ready(req);
+ return;
+ }
- status = smb2cli_session_set_session_key(session,
- state->ntlmssp_state->session_key,
- recv_iov);
- if (tevent_req_nterror(req, status)) {
- return;
- }
- } else {
- struct smbXcli_session *session = state->cli->smb1.session;
+ cli_session_setup_gensec_remote_next(req);
+}
- status = smb1cli_session_set_session_key(session,
- state->ntlmssp_state->session_key);
- if (tevent_req_nterror(req, status)) {
- return;
- }
+static void cli_session_setup_gensec_remote_next(struct tevent_req *req)
+{
+ struct cli_session_setup_gensec_state *state =
+ tevent_req_data(req,
+ struct cli_session_setup_gensec_state);
+ struct tevent_req *subreq = NULL;
- if (smb1cli_conn_activate_signing(
- state->cli->conn, state->ntlmssp_state->session_key,
- data_blob_null)
- && !smb1cli_conn_check_signing(state->cli->conn, inbuf, 1)) {
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
- 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);
+ if (state->remote_ready) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
return;
}
- if (blob_in.length == 0) {
- tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+ subreq = cli_sesssetup_blob_send(state, state->ev,
+ state->cli, state->blob_out);
+ if (tevent_req_nomem(subreq, req)) {
return;
}
+ tevent_req_set_callback(subreq,
+ cli_session_setup_gensec_remote_done,
+ req);
+}
- 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);
- return;
- }
- }
+static void cli_session_setup_gensec_remote_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 = ntlmssp_update(state->ntlmssp_state, msg_in, &blob_out);
+ state->inbuf = NULL;
+ TALLOC_FREE(state->recv_iov);
- if (!NT_STATUS_IS_OK(status)
- && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- TALLOC_FREE(state->ntlmssp_state);
+ 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_auth(state, blob_out);
- if (tevent_req_nomem(state->blob_out.data, req)) {
- return;
+ if (NT_STATUS_IS_OK(status)) {
+ struct smbXcli_session *session = NULL;
+ bool is_guest = false;
+
+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+ session = state->cli->smb2.session;
+ } else {
+ session = state->cli->smb1.session;
+ }
+
+ is_guest = smbXcli_session_is_guest(session);
+ if (is_guest) {
+ /*
+ * We can't finish the gensec handshake, we don't
+ * have a negotiated session key.
+ *
+ * So just pretend we are completely done.
+ *
+ * Note that smbXcli_session_is_guest()
+ * always returns false if we require signing.
+ */
+ state->blob_in = data_blob_null;
+ state->local_ready = true;
+ }
+
+ state->remote_ready = true;
}
- subreq = cli_sesssetup_blob_send(state, state->ev, state->cli,
- state->blob_out);
- if (tevent_req_nomem(subreq, req)) {
+ 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);
+
+ cli_session_setup_gensec_local_next(req);
}
-static NTSTATUS cli_session_setup_ntlmssp_recv(struct tevent_req *req)
+static void cli_session_setup_gensec_ready(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);
+ const char *server_domain = NULL;
NTSTATUS status;
- if (tevent_req_is_nterror(req, &status)) {
- cli_state_set_uid(state->cli, UID_FIELD_INVALID);
- return status;
+ if (state->blob_in.length != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
}
- return NT_STATUS_OK;
-}
-
-#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)
-{
- char *principal = NULL;
+ if (state->blob_out.length != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
- if (!lp_client_use_spnego_principal() ||
- strequal(principal, ADS_IGNORE_PRINCIPAL)) {
- spnego_principal = NULL;
+ /*
+ * 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;
+ }
}
- 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);
+
+ if (state->is_anonymous) {
+ /*
+ * Windows server does not set the
+ * 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;
}
- if (is_ipaddress(remote_name) ||
- strequal(remote_name, STAR_SMBSERVER)) {
- return NULL;
+
+ status = gensec_session_key(state->auth_generic->gensec_security,
+ state, &state->session_key);
+ if (tevent_req_nterror(req, status)) {
+ return;
}
- DEBUG(3, ("cli_session_setup_spnego: using target "
- "hostname not SPNEGO principal\n"));
+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+ struct smbXcli_session *session = state->cli->smb2.session;
- if (dest_realm) {
- char *realm = strupper_talloc(talloc_tos(), dest_realm);
- if (realm == NULL) {
- return NULL;
+ status = smb2cli_session_set_session_key(session,
+ state->session_key,
+ state->recv_iov);
+ if (tevent_req_nterror(req, status)) {
+ return;
}
- 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());
+ struct smbXcli_session *session = state->cli->smb1.session;
+ bool active;
+
+ status = smb1cli_session_set_session_key(session,
+ state->session_key);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ active = smb1cli_conn_activate_signing(state->cli->conn,
+ state->session_key,
+ data_blob_null);
+ if (active) {
+ bool ok;
+
+ ok = smb1cli_conn_check_signing(state->cli->conn,
+ state->inbuf, 1);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+ }
}
- DEBUG(3, ("cli_session_setup_spnego: guessed server principal=%s\n",
- principal ? principal : "<null>"));
- return principal;
+ tevent_req_done(req);
+}
+
+static NTSTATUS cli_session_setup_gensec_recv(struct tevent_req *req)
+{
+ 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)) {
+ cli_state_set_uid(state->cli, UID_FIELD_INVALID);
+ return status;
+ }
+ return NT_STATUS_OK;
}
-#endif
static char *cli_session_setup_get_account(TALLOC_CTX *mem_ctx,
const char *principal)
****************************************************************************/
struct cli_session_setup_spnego_state {
- struct tevent_context *ev;
- struct cli_state *cli;
- 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 void cli_session_setup_spnego_done(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,
- const char *dest_realm)
+ 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 DATA_BLOB *server_blob;
- NTSTATUS status;
+ const char *user_principal = NULL;
+ const char *user_account = NULL;
+ const char *target_hostname = NULL;
+ const DATA_BLOB *server_blob = NULL;
+ enum credentials_use_kerberos krb5_state;
+ bool try_kerberos = false;
+ bool need_kinit = false;
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);
+ if (user != NULL && strlen(user) != 0) {
+ user_principal = user;
+ user_account = cli_session_setup_get_account(state, user);
+ if (tevent_req_nomem(user_account, req)) {
+ return tevent_req_post(req, ev);
+ }
+ } else {
+ user_principal = NULL;
+ user_account = "";
}
+ 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 (server_blob->length == 0) {
- DEBUG(3,("server didn't supply a full spnego negprot\n"));
- goto ntlmssp;
- }
-
-#if 0
- file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
-#endif
-
- /* The server sent us the first part of the SPNEGO exchange in the
- * 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(state, *server_blob, OIDs,
- &principal, NULL) ||
- OIDs[0] == NULL) {
- state->result = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
- tevent_req_done(req);
- return tevent_req_post(req, ev);
- }
+ if (server_blob != NULL && server_blob->length != 0) {
+ char *principal = NULL;
+ char *OIDs[ASN1_MAX_OIDS];
+ int i;
+
+ /* The server sent us the first part of the SPNEGO exchange in the
+ * 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(state, *server_blob, OIDs,
+ &principal, NULL) ||
+ OIDs[0] == NULL) {
+ state->result = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
+ TALLOC_FREE(principal);
+
+ /* make sure the server understands kerberos */
+ for (i = 0; OIDs[i] != NULL; i++) {
+ if (i == 0) {
+ DEBUG(3,("got OID=%s\n", OIDs[i]));
+ } else {
+ DEBUGADD(3,("got OID=%s\n", OIDs[i]));
+ }
- /* make sure the server understands kerberos */
- for (i=0;OIDs[i];i++) {
- if (i == 0)
- DEBUG(3,("got OID=%s\n", OIDs[i]));
- else
- DEBUGADD(3,("got OID=%s\n", OIDs[i]));
- if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
- strcmp(OIDs[i], OID_KERBEROS5) == 0) {
- cli->got_kerberos_mechanism = True;
+ if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
+ strcmp(OIDs[i], OID_KERBEROS5) == 0) {
+ cli->got_kerberos_mechanism = True;
+ }
+ talloc_free(OIDs[i]);
}
- talloc_free(OIDs[i]);
}
- DEBUG(3,("got principal=%s\n", principal ? principal : "<null>"));
+ if (cli->use_kerberos) {
+ if (cli->fallback_after_kerberos) {
+ krb5_state = CRED_AUTO_USE_KERBEROS;
+ } else {
+ krb5_state = CRED_MUST_USE_KERBEROS;
+ }
+ } else {
+ krb5_state = CRED_DONT_USE_KERBEROS;
+ }
- status = cli_set_username(cli, user);
- if (!NT_STATUS_IS_OK(status)) {
- state->result = ADS_ERROR_NT(status);
- tevent_req_done(req);
- return tevent_req_post(req, ev);
+ if (krb5_state != CRED_DONT_USE_KERBEROS) {
+ try_kerberos = true;
+ }
+
+ if (target_hostname == NULL) {
+ try_kerberos = false;
+ } else if (is_ipaddress(target_hostname)) {
+ try_kerberos = false;
+ } else if (strequal(target_hostname, "localhost")) {
+ try_kerberos = false;
+ } else if (strequal(target_hostname, STAR_SMBSERVER)) {
+ try_kerberos = false;
+ } else if (user_principal == NULL) {
+ try_kerberos = false;
}
-#ifdef HAVE_KRB5
- /* If password is set we reauthenticate to kerberos server
- * and do not store results */
+ if (krb5_state == CRED_MUST_USE_KERBEROS && !try_kerberos) {
+ DEBUG(0, ("Kerberos auth with '%s' to access '%s' not possible\n",
+ user_principal, target_hostname));
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return tevent_req_post(req, ev);
+ }
- if (user && *user && cli->got_kerberos_mechanism && cli->use_kerberos) {
- const char *remote_name = smbXcli_conn_remote_name(cli->conn);
- char *tmp;
+ if (pass == NULL || strlen(pass) == 0) {
+ need_kinit = false;
+ } else if (krb5_state == CRED_MUST_USE_KERBEROS) {
+ need_kinit = try_kerberos;
+ } else if (!cli->got_kerberos_mechanism) {
+ /*
+ * Most likely the server doesn't support
+ * Kerberos, don't waste time doing a kinit
+ */
+ need_kinit = false;
+ } else {
+ need_kinit = try_kerberos;
+ }
- if (pass && *pass) {
- int ret;
+ if (need_kinit) {
+ int ret;
- use_in_memory_ccache();
- ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL);
+ use_in_memory_ccache();
+ ret = kerberos_kinit_password(user_principal, pass,
+ 0 /* no time correction for now */,
+ NULL);
- if (ret){
- TALLOC_FREE(principal);
- DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
- if (cli->fallback_after_kerberos)
- goto ntlmssp;
+ if (ret != 0) {
+ DEBUG(0, ("Kinit for %s to access %s failed: %s\n",
+ user_principal, target_hostname,
+ error_message(ret)));
+ if (krb5_state == CRED_MUST_USE_KERBEROS) {
state->result = ADS_ERROR_KRB5(ret);
tevent_req_done(req);
return tevent_req_post(req, ev);
}
- }
-
- tmp = cli_session_setup_get_principal(
- talloc_tos(), principal, remote_name, dest_realm);
- TALLOC_FREE(principal);
- principal = tmp;
- if (principal) {
- subreq = cli_session_setup_kerberos_send(
- state, ev, cli, 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;
+ /*
+ * Ignore the error and hope that NTLM will work
+ */
+ ret = 0;
}
}
-#endif
-ntlmssp:
- subreq = cli_session_setup_ntlmssp_send(
- state, ev, cli, state->account, pass, user_domain);
+ subreq = cli_session_setup_gensec_send(state, ev, cli,
+ user_account,
+ pass,
+ user_domain,
+ krb5_state,
+ "cifs",
+ target_hostname);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
tevent_req_set_callback(
- subreq, cli_session_setup_spnego_done_ntlmssp, req);
+ subreq, cli_session_setup_spnego_done, req);
return req;
}
-#ifdef HAVE_KRB5
-static void cli_session_setup_spnego_done_krb(struct tevent_req *subreq)
+static void cli_session_setup_spnego_done(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;
- state->result = cli_session_setup_kerberos_recv(subreq);
+ status = cli_session_setup_gensec_recv(subreq);
TALLOC_FREE(subreq);
-
- if (ADS_ERR_OK(state->result) ||
- !state->cli->fallback_after_kerberos) {
- tevent_req_done(req);
- return;
- }
-
- subreq = cli_session_setup_ntlmssp_send(
- state, state->ev, state->cli, state->account, state->pass,
- state->user_domain);
- if (tevent_req_nomem(subreq, req)) {
+ if (tevent_req_nterror(req, status)) {
return;
}
- tevent_req_set_callback(subreq, cli_session_setup_spnego_done_ntlmssp,
- req);
-}
-#endif
-
-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;
- status = cli_session_setup_ntlmssp_recv(subreq);
- TALLOC_FREE(subreq);
- state->result = ADS_ERROR_NT(status);
tevent_req_done(req);
}
{
struct cli_session_setup_spnego_state *state = tevent_req_data(
req, struct cli_session_setup_spnego_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ state->result = ADS_ERROR_NT(status);
+ }
return state->result;
}
struct cli_session_setup_state {
- uint8_t dummy;
+ struct cli_state *cli;
+ uint8_t nt_hash[16];
+ uint8_t lm_hash[16];
+ DATA_BLOB apassword_blob;
+ DATA_BLOB upassword_blob;
+ DATA_BLOB lm_session_key;
+ DATA_BLOB session_key;
+ char *out_native_os;
+ char *out_native_lm;
+ char *out_primary_domain;
};
-static void cli_session_setup_done_lanman2(struct tevent_req *subreq);
+static void cli_session_setup_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct cli_session_setup_state *state = tevent_req_data(
+ req, struct cli_session_setup_state);
+
+ if (req_state != TEVENT_REQ_RECEIVED) {
+ return;
+ }
+
+ /*
+ * We only call data_blob_clear() as
+ * some of the blobs point to the same memory.
+ *
+ * We let the talloc hierachy free the memory.
+ */
+ data_blob_clear(&state->apassword_blob);
+ data_blob_clear(&state->upassword_blob);
+ data_blob_clear(&state->lm_session_key);
+ data_blob_clear(&state->session_key);
+ ZERO_STRUCTP(state);
+}
+
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);
+static void cli_session_setup_done_lm21(struct tevent_req *subreq);
/****************************************************************************
Send a session setup. The username and workgroup is in UNIX character
struct tevent_context *ev,
struct cli_state *cli,
const char *user,
- const char *pass, int passlen,
- const char *ntpass, int ntpasslen,
+ const char *pass,
const char *workgroup)
{
struct tevent_req *req, *subreq;
char *p;
char *user2;
uint16_t sec_mode = smb1cli_conn_server_security_mode(cli->conn);
+ bool use_spnego = false;
+ bool do_lmresponse = false;
+ const char *username = "";
+ const char *domain = "";
+ const char *password = "";
+ DATA_BLOB target_info = data_blob_null;
+ DATA_BLOB challenge = data_blob_null;
+ uint16_t in_buf_size = 0;
+ uint16_t in_mpx_max = 0;
+ uint16_t in_vc_num = 0;
+ uint32_t in_sess_key = 0;
+ const char *in_native_os = NULL;
+ const char *in_native_lm = NULL;
req = tevent_req_create(mem_ctx, &state,
struct cli_session_setup_state);
if (req == NULL) {
return NULL;
}
+ state->cli = cli;
+
+ tevent_req_set_cleanup_fn(req, cli_session_setup_cleanup);
if (user) {
user2 = talloc_strdup(state, user);
workgroup = user2;
}
+ /*
+ * Now work out what sort of session setup we are going to
+ * do. I have split this into separate functions to make the flow a bit
+ * easier to understand (tridge).
+ */
+ if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_NT1) {
+ use_spnego = false;
+ } else if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ use_spnego = true;
+ } else if (smb1cli_conn_capabilities(cli->conn) & CAP_EXTENDED_SECURITY) {
+ /*
+ * if the server supports extended security then use SPNEGO
+ * even for anonymous connections.
+ */
+ use_spnego = true;
+ } else {
+ use_spnego = false;
+ }
+
+ if (use_spnego) {
+ 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 (smbXcli_conn_protocol(cli->conn) < PROTOCOL_LANMAN1) {
+ /*
+ * SessionSetupAndX was introduced by LANMAN 1.0. So we skip
+ * this step against older servers.
+ */
tevent_req_done(req);
return tevent_req_post(req, ev);
}
- /* now work out what sort of session setup we are going to
- do. I have split this into separate functions to make the
- flow a bit easier to understand (tridge) */
+ if (user == NULL || strlen(user) == 0) {
+ /*
+ * Do an anonymous session setup
+ */
+ goto non_spnego_creds_done;
+ }
+
+ if ((sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0) {
+ /*
+ * Do an anonymous session setup,
+ * the password is passed via the tree connect.
+ */
+ goto non_spnego_creds_done;
+ }
- /* if its an older server then we have to use the older request format */
+ username = user;
+ domain = workgroup;
+ if (pass != NULL) {
+ password = pass;
+ }
- 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"));
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
- return tevent_req_post(req, ev);
+ if ((sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
+ bool use_unicode = smbXcli_conn_use_unicode(cli->conn);
+ uint8_t *bytes = NULL;
+ size_t bytes_len = 0;
+ const char *pw = password;
+ size_t pw_len = 0;
+
+ if (pw == NULL) {
+ pw = "";
}
+ pw_len = strlen(pw) + 1;
- if ((sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
- !lp_client_plaintext_auth() && (*pass)) {
- DEBUG(1, ("Server requested PLAINTEXT password but 'client plaintext auth = no'"
- " or 'client ntlmv2 auth = yes'\n"));
+ if (!lp_client_plaintext_auth()) {
+ DEBUG(1, ("Server requested PLAINTEXT password but "
+ "'client plaintext auth = no'\n"));
tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
return tevent_req_post(req, ev);
}
- subreq = cli_session_setup_lanman2_send(
- state, ev, cli, user, pass, passlen, workgroup);
- if (tevent_req_nomem(subreq, req)) {
+ bytes = talloc_array(state, uint8_t, 0);
+ bytes = trans2_bytes_push_str(bytes, use_unicode,
+ pw, pw_len, &bytes_len);
+ if (tevent_req_nomem(bytes, req)) {
return tevent_req_post(req, ev);
}
- tevent_req_set_callback(subreq, cli_session_setup_done_lanman2,
- req);
- return req;
+
+ if (use_unicode) {
+ /*
+ * CAP_UNICODE, can only be negotiated by NT1.
+ */
+ state->upassword_blob = data_blob_const(bytes,
+ bytes_len);
+ } else {
+ state->apassword_blob = data_blob_const(bytes,
+ bytes_len);
+ }
+
+ goto non_spnego_creds_done;
}
- if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
- const char *remote_realm = cli_state_remote_realm(cli);
+ challenge = data_blob_const(smb1cli_conn_server_challenge(cli->conn), 8);
+ E_md4hash(password, state->nt_hash);
- subreq = cli_session_setup_spnego_send(
- state, ev, cli, user, pass, workgroup, remote_realm);
- if (tevent_req_nomem(subreq, req)) {
+ if (smbXcli_conn_protocol(cli->conn) == PROTOCOL_NT1) {
+ 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' is set\n"));
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
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 (lp_client_ntlmv2_auth()) {
+ bool ok;
- if (!user || !*user) {
- subreq = cli_session_setup_guest_send(state, ev, cli);
- if (tevent_req_nomem(subreq, req)) {
+ /*
+ * note that the 'domain' here is a best
+ * guess - we don't know the server's domain
+ * at this point. Windows clients also don't
+ * use hostname...
+ */
+ target_info = NTLMv2_generate_names_blob(state,
+ NULL,
+ domain);
+ if (tevent_req_nomem(target_info.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ ok = SMBNTLMv2encrypt_hash(state,
+ username,
+ domain,
+ state->nt_hash,
+ &challenge,
+ NULL, /* server_timestamp */
+ &target_info,
+ &state->apassword_blob,
+ &state->upassword_blob,
+ &state->lm_session_key,
+ &state->session_key);
+ if (!ok) {
+ tevent_req_nterror(req,
+ NT_STATUS_ACCESS_DENIED);
+ return tevent_req_post(req, ev);
+ }
+ } else {
+ state->upassword_blob = data_blob_talloc_zero(state, 24);
+ if (tevent_req_nomem(state->upassword_blob.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+ state->session_key = data_blob_talloc_zero(state, 16);
+ if (tevent_req_nomem(state->session_key.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ SMBNTencrypt_hash(state->nt_hash, challenge.data,
+ state->upassword_blob.data);
+ SMBsesskeygen_ntv1(state->nt_hash,
+ state->session_key.data);
+
+ if (lp_client_lanman_auth()) {
+ do_lmresponse = E_deshash(password,
+ state->lm_hash);
+ }
+ }
+ } else {
+ if (!lp_client_lanman_auth()) {
+ DEBUG(1, ("Server requested LM password but "
+ "'client lanman auth = no' "
+ "or 'client ntlmv2 auth = yes' is set\n"));
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
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 */
+ do_lmresponse = E_deshash(password, state->lm_hash);
+ }
- 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)) {
+ if (do_lmresponse) {
+ state->apassword_blob = data_blob_talloc_zero(state, 24);
+ if (tevent_req_nomem(state->apassword_blob.data, 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 */
+ SMBencrypt_hash(state->lm_hash,
+ challenge.data,
+ state->apassword_blob.data);
+ }
- if ((sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
- if (!lp_client_plaintext_auth() && (*pass)) {
- DEBUG(1, ("Server requested PLAINTEXT password but 'client plaintext auth = no'"
- " or 'client ntlmv2 auth = yes'\n"));
+ if (state->apassword_blob.length == 0) {
+ if (state->upassword_blob.length == 0) {
+ DEBUG(1, ("Password is > 14 chars in length, and is "
+ "therefore incompatible with Lanman "
+ "authentication\n"));
tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
return tevent_req_post(req, ev);
}
- 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;
+
+ /*
+ * LM disabled, place NT# in LM field
+ * instead
+ */
+ state->apassword_blob = state->upassword_blob;
}
- /* if the server supports extended security then use SPNEGO */
+non_spnego_creds_done:
- if (smb1cli_conn_capabilities(cli->conn) & CAP_EXTENDED_SECURITY) {
- const char *remote_realm = cli_state_remote_realm(cli);
+ in_buf_size = CLI_BUFFER_SIZE;
+ in_mpx_max = smbXcli_conn_max_requests(cli->conn);
+ in_vc_num = cli_state_get_vc_num(cli);
+ in_sess_key = smb1cli_conn_server_session_key(cli->conn);
+ in_native_os = "Unix";
+ in_native_lm = "Samba";
- subreq = cli_session_setup_spnego_send(
- state, ev, cli, user, pass, workgroup, remote_realm);
- 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 {
- /* otherwise do a NT1 style session setup */
+ if (smbXcli_conn_protocol(cli->conn) == PROTOCOL_NT1) {
+ uint32_t in_capabilities = 0;
- subreq = cli_session_setup_nt1_send(
- state, ev, cli, user, pass, passlen, ntpass, ntpasslen,
- workgroup);
+ in_capabilities = cli_session_setup_capabilities(cli, 0);
+
+ /*
+ * For now we keep the same values as before,
+ * we may remove these in a separate commit later.
+ */
+ in_mpx_max = 2;
+
+ subreq = smb1cli_session_setup_nt1_send(state, ev,
+ cli->conn,
+ cli->timeout,
+ cli->smb1.pid,
+ cli->smb1.session,
+ in_buf_size,
+ in_mpx_max,
+ in_vc_num,
+ in_sess_key,
+ username,
+ domain,
+ state->apassword_blob,
+ state->upassword_blob,
+ in_capabilities,
+ in_native_os,
+ in_native_lm);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
return req;
}
- 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;
+ /*
+ * For now we keep the same values as before,
+ * we may remove these in a separate commit later.
+ */
+ in_mpx_max = 2;
+ in_vc_num = 1;
+
+ subreq = smb1cli_session_setup_lm21_send(state, ev,
+ cli->conn,
+ cli->timeout,
+ cli->smb1.pid,
+ cli->smb1.session,
+ in_buf_size,
+ in_mpx_max,
+ in_vc_num,
+ in_sess_key,
+ username,
+ domain,
+ state->apassword_blob,
+ in_native_os,
+ in_native_lm);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
- tevent_req_done(req);
+ tevent_req_set_callback(subreq, cli_session_setup_done_lm21,
+ req);
+ return req;
}
static void cli_session_setup_done_spnego(struct tevent_req *subreq)
tevent_req_done(req);
}
-static void cli_session_setup_done_guest(struct tevent_req *subreq)
+static void cli_session_setup_done_nt1(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
+ struct cli_session_setup_state *state = tevent_req_data(
+ req, struct cli_session_setup_state);
+ struct cli_state *cli = state->cli;
NTSTATUS status;
-
- status = cli_session_setup_guest_recv(subreq);
+ struct iovec *recv_iov = NULL;
+ const uint8_t *inbuf = NULL;
+ bool ok;
+
+ status = smb1cli_session_setup_nt1_recv(subreq, state,
+ &recv_iov,
+ &inbuf,
+ &state->out_native_os,
+ &state->out_native_lm,
+ &state->out_primary_domain);
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("NT1 login failed: %s\n", nt_errstr(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;
+ if (cli->server_os == NULL) {
+ cli->server_os = talloc_move(cli, &state->out_native_os);
+ }
+ if (cli->server_type == NULL) {
+ cli->server_type = talloc_move(cli, &state->out_native_lm);
+ }
+ if (cli->server_domain == NULL) {
+ cli->server_domain = talloc_move(cli, &state->out_primary_domain);
+ }
- status = cli_session_setup_plain_recv(subreq);
- TALLOC_FREE(subreq);
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
+ ok = smb1cli_conn_activate_signing(cli->conn,
+ state->session_key,
+ state->upassword_blob);
+ if (ok) {
+ ok = smb1cli_conn_check_signing(cli->conn, inbuf, 1);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+ }
+
+ if (state->session_key.data) {
+ struct smbXcli_session *session = cli->smb1.session;
+
+ status = smb1cli_session_set_session_key(session,
+ state->session_key);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
}
+
tevent_req_done(req);
}
-static void cli_session_setup_done_nt1(struct tevent_req *subreq)
+static void cli_session_setup_done_lm21(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
+ struct cli_session_setup_state *state = tevent_req_data(
+ req, struct cli_session_setup_state);
+ struct cli_state *cli = state->cli;
NTSTATUS status;
- status = cli_session_setup_nt1_recv(subreq);
+ status = smb1cli_session_setup_lm21_recv(subreq, state,
+ &state->out_native_os,
+ &state->out_native_lm);
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(3, ("cli_session_setup: NT1 session setup "
- "failed: %s\n", nt_errstr(status)));
+ DEBUG(3, ("LM21 login failed: %s\n", nt_errstr(status)));
tevent_req_nterror(req, status);
return;
}
+
+ if (cli->server_os == NULL) {
+ cli->server_os = talloc_move(cli, &state->out_native_os);
+ }
+ if (cli->server_type == NULL) {
+ cli->server_type = talloc_move(cli, &state->out_native_lm);
+ }
+
tevent_req_done(req);
}
NTSTATUS cli_session_setup(struct cli_state *cli,
const char *user,
- const char *pass, int passlen,
- const char *ntpass, int ntpasslen,
+ const char *pass,
const char *workgroup)
{
struct tevent_context *ev;
if (ev == NULL) {
goto fail;
}
- req = cli_session_setup_send(ev, ev, cli, user, pass, passlen,
- ntpass, ntpasslen, workgroup);
+ req = cli_session_setup_send(ev, ev, cli, user, pass, workgroup);
if (req == NULL) {
goto fail;
}
SCVAL(state->vwv+1, 0, 0);
SSVAL(state->vwv+2, 0, 0);
- subreq = cli_smb_send(state, ev, cli, SMBulogoffX, 0, 2, state->vwv,
+ subreq = cli_smb_send(state, ev, cli, SMBulogoffX, 0, 0, 2, state->vwv,
0, NULL);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
* 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);
}
state->bytes.iov_base = (void *)bytes;
state->bytes.iov_len = talloc_get_size(bytes);
- subreq = cli_smb_req_create(state, ev, cli, SMBtconX, 0, 4, vwv,
+ subreq = cli_smb_req_create(state, ev, cli, SMBtconX, 0, 0, 4, vwv,
1, &state->bytes);
if (subreq == NULL) {
TALLOC_FREE(req);
* 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 (optional_support & SMB_SHARE_IN_DFS) {
- cli->dfsroot = true;
- }
-
if (optional_support & SMB_EXTENDED_SIGNATURES) {
smb1cli_session_protect_session_key(cli->smb1.session);
}
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 *max_xmit, uint16 *tid);
+ 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);
}
if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
- subreq = smb2cli_tcon_send(state, ev, cli, share);
+ 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);
}
}
state->cli = cli;
- subreq = cli_smb_send(state, ev, cli, SMBtdis, 0, 0, NULL, 0, NULL);
+ subreq = cli_smb_send(state, ev, cli, SMBtdis, 0, 0, 0, NULL, 0, NULL);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
NTSTATUS status = NT_STATUS_NO_MEMORY;
if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
- return smb2cli_tdis(cli);
+ return smb2cli_tdis(cli->conn,
+ cli->timeout,
+ cli->smb2.session,
+ cli->smb2.tcon);
}
if (smbXcli_conn_has_async_calls(cli->conn)) {
struct tevent_req *req, *subreq;
struct cli_connect_sock_state *state;
const char *prog;
+ struct sockaddr_storage *addrs;
unsigned i, num_addrs;
NTSTATUS status;
}
if ((pss == NULL) || is_zero_addr(pss)) {
- struct sockaddr_storage *addrs;
/*
* Here we cheat. resolve_name_list is not async at all. So
tevent_req_nterror(req, status);
return tevent_req_post(req, ev);
}
- pss = addrs;
} 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;
}
}
subreq = smbsock_any_connect_send(
- state, ev, pss, state->called_names, state->called_types,
+ 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);
{
struct tevent_req *req, *subreq;
struct cli_connect_nb_state *state;
- char *p;
req = tevent_req_create(mem_ctx, &state, struct cli_connect_nb_state);
if (req == NULL) {
return NULL;
}
- state->desthost = host;
state->signing_state = signing_state;
state->flags = flags;
- p = strchr(host, '#');
- if (p != NULL) {
- name_type = strtol(p+1, NULL, 16);
- host = talloc_strndup(state, host, p - host);
- if (tevent_req_nomem(host, req)) {
+ if (host != NULL) {
+ char *p = strchr(host, '#');
+
+ 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);
+ }
+ }
+
+ state->desthost = host;
+ } else if (dest_ss != NULL) {
+ state->desthost = print_canonical_sockaddr(state, dest_ss);
+ if (tevent_req_nomem(state->desthost, req)) {
return tevent_req_post(req, ev);
}
+ } else {
+ /* No host or dest_ss given. Error out. */
+ tevent_req_error(req, EINVAL);
+ return tevent_req_post(req, ev);
}
subreq = cli_connect_sock_send(state, ev, host, name_type, dest_ss,
struct cli_connect_nb_state *state = tevent_req_data(
req, struct cli_connect_nb_state);
NTSTATUS status;
- int fd;
+ int fd = 0;
uint16_t port;
status = cli_connect_sock_recv(subreq, &fd, &port);
struct cli_start_connection_state {
struct tevent_context *ev;
struct cli_state *cli;
+ int min_protocol;
+ int max_protocol;
};
static void cli_start_connection_connected(struct tevent_req *subreq);
}
state->ev = ev;
+ 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();
+ }
+
subreq = cli_connect_nb_send(state, ev, dest_host, dest_ss, port,
0x20, my_name, signing_state, flags);
if (tevent_req_nomem(subreq, req)) {
subreq = smbXcli_negprot_send(state, state->ev, state->cli->conn,
state->cli->timeout,
- lp_cli_minprotocol(),
- lp_cli_maxprotocol());
+ state->min_protocol,
+ state->max_protocol);
if (tevent_req_nomem(subreq, req)) {
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);
+ state->password, state->domain);
if (tevent_req_nomem(subreq, req)) {
return;
}
state->flags &= ~CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK;
subreq = cli_session_setup_send(
- state, state->ev, state->cli, "", "", 0, "", 0,
+ state, state->ev, state->cli, "", "",
state->domain);
if (tevent_req_nomem(subreq, req)) {
return;
return;
}
- status = cli_init_creds(state->cli, state->user, state->domain,
- state->password);
- if (tevent_req_nterror(req, status)) {
- return;
- }
tevent_req_done(req);
}
{
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_tree_connect_recv(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
- status = cli_init_creds(state->cli, state->user, state->domain,
- state->password);
- if (tevent_req_nterror(req, status)) {
- return;
- }
+
tevent_req_done(req);
}
return tevent_req_post(req, ev);
}
- subreq = cli_smb_send(state, ev, cli, SMBtcon, 0, 0, NULL,
+ subreq = cli_smb_send(state, ev, cli, SMBtcon, 0, 0, 0, NULL,
talloc_get_size(bytes), bytes);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
static NTSTATUS cli_raw_tcon_recv(struct tevent_req *req,
- uint16 *max_xmit, uint16 *tid)
+ uint16_t *max_xmit, uint16_t *tid)
{
struct cli_raw_tcon_state *state = tevent_req_data(
req, struct cli_raw_tcon_state);
NTSTATUS cli_raw_tcon(struct cli_state *cli,
const char *service, const char *pass, const char *dev,
- uint16 *max_xmit, uint16 *tid)
+ uint16_t *max_xmit, uint16_t *tid)
{
struct tevent_context *ev;
struct tevent_req *req;
NTSTATUS nt_status;
uint32_t flags = CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK;
- if (user_info->use_kerberos) {
+ if (get_cmdline_auth_info_use_kerberos(user_info)) {
flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
}
nt_status = cli_full_connection(&cli, NULL, server, server_ss, 0, "IPC$", "IPC",
- user_info->username ? user_info->username : "",
+ get_cmdline_auth_info_username(user_info),
lp_workgroup(),
- user_info->password ? user_info->password : "",
+ get_cmdline_auth_info_password(user_info),
flags,
SMB_SIGNING_DEFAULT);