summaryrefslogtreecommitdiff
path: root/source3/libsmb
diff options
context:
space:
mode:
Diffstat (limited to 'source3/libsmb')
-rw-r--r--source3/libsmb/cliconnect.c6
-rw-r--r--source3/libsmb/clientgen.c42
-rw-r--r--source3/libsmb/ntlmssp.c107
-rw-r--r--source3/libsmb/ntlmssp_parse.c75
-rw-r--r--source3/libsmb/ntlmssp_sign.c206
-rw-r--r--source3/libsmb/pwd_cache.c14
-rw-r--r--source3/libsmb/smbencrypt.c31
7 files changed, 385 insertions, 96 deletions
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index 18125e26c3..cdd80b7f0c 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -540,6 +540,12 @@ static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
ntlmssp_state->use_ntlmv2 = lp_client_ntlmv2_auth();
+ if (cli->sign_info.negotiated_smb_signing
+ || cli->sign_info.mandetory_signing) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
+ }
+
do {
nt_status = ntlmssp_client_update(ntlmssp_state,
blob_in, &blob_out);
diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c
index 8d4e8a266c..93fa94c1db 100644
--- a/source3/libsmb/clientgen.c
+++ b/source3/libsmb/clientgen.c
@@ -203,12 +203,9 @@ void cli_init_creds(struct cli_state *cli, const struct ntuser_creds *usr)
fstrcpy(cli->domain , usr->domain);
fstrcpy(cli->user_name, usr->user_name);
memcpy(&cli->pwd, &usr->pwd, sizeof(usr->pwd));
- cli->ntlmssp_flags = usr->ntlmssp_flags;
- cli->ntlmssp_cli_flgs = usr != NULL ? usr->ntlmssp_flags : 0;
- DEBUG(10,("cli_init_creds: user %s domain %s flgs: %x\nntlmssp_cli_flgs:%x\n",
- cli->user_name, cli->domain,
- cli->ntlmssp_flags,cli->ntlmssp_cli_flgs));
+ DEBUG(10,("cli_init_creds: user %s domain %s\n",
+ cli->user_name, cli->domain));
}
/****************************************************************************
@@ -287,6 +284,8 @@ struct cli_state *cli_initialise(struct cli_state *cli)
cli->initialised = 1;
cli->allocated = alloced_cli;
+ cli->pipe_idx = -1;
+
return cli;
/* Clean up after malloc() error */
@@ -303,17 +302,50 @@ struct cli_state *cli_initialise(struct cli_state *cli)
}
/****************************************************************************
+close the session
+****************************************************************************/
+
+void cli_nt_session_close(struct cli_state *cli)
+{
+ if (cli->ntlmssp_pipe_state) {
+ ntlmssp_client_end(&cli->ntlmssp_pipe_state);
+ }
+
+ cli_close(cli, cli->nt_pipe_fnum);
+ cli->nt_pipe_fnum = 0;
+ cli->pipe_idx = -1;
+}
+
+/****************************************************************************
+close the NETLOGON session holding the session key for NETSEC
+****************************************************************************/
+
+void cli_nt_netlogon_netsec_session_close(struct cli_state *cli)
+{
+ if (cli->saved_netlogon_pipe_fnum != 0) {
+ cli_close(cli, cli->saved_netlogon_pipe_fnum);
+ cli->saved_netlogon_pipe_fnum = 0;
+ }
+}
+
+/****************************************************************************
Close a client connection and free the memory without destroying cli itself.
****************************************************************************/
void cli_close_connection(struct cli_state *cli)
{
+ cli_nt_session_close(cli);
+ cli_nt_netlogon_netsec_session_close(cli);
+
SAFE_FREE(cli->outbuf);
SAFE_FREE(cli->inbuf);
cli_free_signing_context(cli);
data_blob_free(&cli->secblob);
+ if (cli->ntlmssp_pipe_state)
+ ntlmssp_client_end(&cli->ntlmssp_pipe_state);
+
if (cli->mem_ctx) {
talloc_destroy(cli->mem_ctx);
cli->mem_ctx = NULL;
diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c
index 4dc9d42659..66dc6e08eb 100644
--- a/source3/libsmb/ntlmssp.c
+++ b/source3/libsmb/ntlmssp.c
@@ -409,6 +409,10 @@ static NTSTATUS ntlmssp_client_initial(struct ntlmssp_client_state *ntlmssp_stat
ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
}
+ if (ntlmssp_state->use_ntlmv2) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
+ }
+
/* generate the ntlmssp negotiate packet */
msrpc_gen(next_request, "CddAA",
"NTLMSSP",
@@ -435,7 +439,7 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
uint32 chal_flags, ntlmssp_command, unkn1, unkn2;
DATA_BLOB server_domain_blob;
DATA_BLOB challenge_blob;
- DATA_BLOB struct_blob;
+ DATA_BLOB struct_blob = data_blob(NULL, 0);
char *server_domain;
const char *chal_parse_string;
const char *auth_gen_string;
@@ -443,28 +447,48 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
DATA_BLOB nt_response = data_blob(NULL, 0);
DATA_BLOB session_key = data_blob(NULL, 0);
uint8 datagram_sess_key[16];
+ size_t datagram_sess_key_len;
+#if 0 /* until we know what flag to tigger it on */
generate_random_buffer(datagram_sess_key, sizeof(datagram_sess_key), False);
+ datagram_sess_key_len = sizeof(datagram_sess_key);
+#else
+ ZERO_STRUCT(datagram_sess_key);
+ datagram_sess_key_len = 0;
+#endif
if (!msrpc_parse(&reply, "CdBd",
"NTLMSSP",
&ntlmssp_command,
&server_domain_blob,
&chal_flags)) {
- DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
+ DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
+ dump_data(2, reply.data, reply.length);
+
return NT_STATUS_INVALID_PARAMETER;
}
data_blob_free(&server_domain_blob);
+ DEBUG(3, ("Got challenge flags:\n"));
+ debug_ntlmssp_flags(chal_flags);
+
if (chal_flags & NTLMSSP_NEGOTIATE_UNICODE) {
- chal_parse_string = "CdUdbddB";
+ if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
+ chal_parse_string = "CdUdbddB";
+ } else {
+ chal_parse_string = "CdUdbdd";
+ }
auth_gen_string = "CdBBUUUBd";
ntlmssp_state->unicode = True;
ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM;
} else if (chal_flags & NTLMSSP_NEGOTIATE_OEM) {
- chal_parse_string = "CdAdbddB";
+ if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
+ chal_parse_string = "CdAdbddB";
+ } else {
+ chal_parse_string = "CdAdbdd";
+ }
auth_gen_string = "CdBBAAABd";
ntlmssp_state->unicode = False;
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE;
@@ -473,6 +497,25 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
return NT_STATUS_INVALID_PARAMETER;
}
+ if (chal_flags & NTLMSSP_NEGOTIATE_LM_KEY && lp_client_lanman_auth()) {
+ /* server forcing us to use LM */
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
+ ntlmssp_state->use_ntlmv2 = False;
+ } else {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
+ }
+
+ if (!(chal_flags & NTLMSSP_NEGOTIATE_NTLM2)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
+ }
+
+ if (!(chal_flags & NTLMSSP_NEGOTIATE_128)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128;
+ }
+
+ DEBUG(3, ("NTLMSSP: Set final flags:\n"));
+ debug_ntlmssp_flags(ntlmssp_state->neg_flags);
+
if (!msrpc_parse(&reply, chal_parse_string,
"NTLMSSP",
&ntlmssp_command,
@@ -481,7 +524,8 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
&challenge_blob, 8,
&unkn1, &unkn2,
&struct_blob)) {
- DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
+ DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n"));
+ dump_data(2, reply.data, reply.length);
return NT_STATUS_INVALID_PARAMETER;
}
@@ -493,6 +537,11 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
if (ntlmssp_state->use_ntlmv2) {
+ if (!struct_blob.length) {
+ /* be lazy, match win2k - we can't do NTLMv2 without it */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
/* TODO: if the remote server is standalone, then we should replace 'domain'
with the server name as supplied above */
@@ -506,10 +555,12 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
return NT_STATUS_NO_MEMORY;
}
} else {
+ uchar lm_hash[16];
uchar nt_hash[16];
+ E_deshash(ntlmssp_state->password, lm_hash);
E_md4hash(ntlmssp_state->password, nt_hash);
- /* non encrypted password supplied. Ignore ntpass. */
+ /* lanman auth is insecure, it may be disabled */
if (lp_client_lanman_auth()) {
lm_response = data_blob(NULL, 24);
SMBencrypt(ntlmssp_state->password,challenge_blob.data,
@@ -519,8 +570,15 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
nt_response = data_blob(NULL, 24);
SMBNTencrypt(ntlmssp_state->password,challenge_blob.data,
nt_response.data);
+
session_key = data_blob(NULL, 16);
- SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
+ if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY)
+ && lp_client_lanman_auth()) {
+ SMBsesskeygen_lmv1(lm_hash, lm_response.data,
+ session_key.data);
+ } else {
+ SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
+ }
}
data_blob_free(&struct_blob);
@@ -533,7 +591,7 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
ntlmssp_state->domain,
ntlmssp_state->user,
ntlmssp_state->get_global_myname(),
- datagram_sess_key, 16,
+ datagram_sess_key, datagram_sess_key_len,
ntlmssp_state->neg_flags)) {
data_blob_free(&lm_response);
@@ -575,6 +633,8 @@ NTSTATUS ntlmssp_client_start(NTLMSSP_CLIENT_STATE **ntlmssp_state)
(*ntlmssp_state)->unicode = True;
+ (*ntlmssp_state)->use_ntlmv2 = lp_client_ntlmv2_auth();
+
(*ntlmssp_state)->neg_flags =
NTLMSSP_NEGOTIATE_128 |
NTLMSSP_NEGOTIATE_NTLM |
@@ -596,6 +656,7 @@ NTSTATUS ntlmssp_client_end(NTLMSSP_CLIENT_STATE **ntlmssp_state)
data_blob_free(&(*ntlmssp_state)->lm_resp);
data_blob_free(&(*ntlmssp_state)->nt_resp);
data_blob_free(&(*ntlmssp_state)->session_key);
+ data_blob_free(&(*ntlmssp_state)->stored_response);
talloc_destroy(mem_ctx);
}
@@ -606,12 +667,18 @@ NTSTATUS ntlmssp_client_end(NTLMSSP_CLIENT_STATE **ntlmssp_state)
NTSTATUS ntlmssp_client_update(NTLMSSP_CLIENT_STATE *ntlmssp_state,
DATA_BLOB reply, DATA_BLOB *next_request)
{
+ NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
uint32 ntlmssp_command;
*next_request = data_blob(NULL, 0);
if (!reply.length) {
- return ntlmssp_client_initial(ntlmssp_state, reply, next_request);
- }
+ /* If there is a cached reply, use it - otherwise this is the first packet */
+ if (!ntlmssp_state->stored_response.length) {
+ return ntlmssp_client_initial(ntlmssp_state, reply, next_request);
+ }
+
+ reply = ntlmssp_state->stored_response;
+ }
if (!msrpc_parse(&reply, "Cd",
"NTLMSSP",
@@ -620,9 +687,12 @@ NTSTATUS ntlmssp_client_update(NTLMSSP_CLIENT_STATE *ntlmssp_state,
}
if (ntlmssp_command == NTLMSSP_CHALLENGE) {
- return ntlmssp_client_challenge(ntlmssp_state, reply, next_request);
+ nt_status = ntlmssp_client_challenge(ntlmssp_state, reply, next_request);
}
- return NT_STATUS_INVALID_PARAMETER;
+ if (ntlmssp_state->stored_response.length) {
+ data_blob_free(&ntlmssp_state->stored_response);
+ }
+ return nt_status;
}
NTSTATUS ntlmssp_set_username(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *user)
@@ -651,3 +721,16 @@ NTSTATUS ntlmssp_set_domain(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *dom
}
return NT_STATUS_OK;
}
+
+/**
+ * Store a DATA_BLOB containing an NTLMSSP response, for use later.
+ * This 'keeps' the data blob - the caller must *not* free it.
+ */
+
+NTSTATUS ntlmssp_client_store_response(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+ DATA_BLOB response)
+{
+ data_blob_free(&ntlmssp_state->stored_response);
+ ntlmssp_state->stored_response = response;
+ return NT_STATUS_OK;
+}
diff --git a/source3/libsmb/ntlmssp_parse.c b/source3/libsmb/ntlmssp_parse.c
index ac779a3906..f53afcdcd0 100644
--- a/source3/libsmb/ntlmssp_parse.c
+++ b/source3/libsmb/ntlmssp_parse.c
@@ -220,23 +220,27 @@ BOOL msrpc_parse(const DATA_BLOB *blob,
len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
- /* make sure its in the right format - be strict */
- if (len1 != len2 || ptr + len1 > blob->length) {
- return False;
- }
- if (len1 & 1) {
- /* if odd length and unicode */
- return False;
- }
-
ps = va_arg(ap, char **);
- if (0 < len1) {
- pull_string(NULL, p, blob->data + ptr, sizeof(p),
- len1,
- STR_UNICODE|STR_NOALIGN);
- (*ps) = smb_xstrdup(p);
+ if (len1 == 0 && len2 == 0) {
+ *ps = smb_xstrdup("");
} else {
- (*ps) = smb_xstrdup("");
+ /* make sure its in the right format - be strict */
+ if (len1 != len2 || ptr + len1 > blob->length) {
+ return False;
+ }
+ if (len1 & 1) {
+ /* if odd length and unicode */
+ return False;
+ }
+
+ if (0 < len1) {
+ pull_string(NULL, p, blob->data + ptr, sizeof(p),
+ len1,
+ STR_UNICODE|STR_NOALIGN);
+ (*ps) = smb_xstrdup(p);
+ } else {
+ (*ps) = smb_xstrdup("");
+ }
}
break;
case 'A':
@@ -245,19 +249,23 @@ BOOL msrpc_parse(const DATA_BLOB *blob,
len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
- /* make sure its in the right format - be strict */
- if (len1 != len2 || ptr + len1 > blob->length) {
- return False;
- }
-
ps = va_arg(ap, char **);
- if (0 < len1) {
- pull_string(NULL, p, blob->data + ptr, sizeof(p),
- len1,
- STR_ASCII|STR_NOALIGN);
- (*ps) = smb_xstrdup(p);
+ /* make sure its in the right format - be strict */
+ if (len1 == 0 && len2 == 0) {
+ *ps = smb_xstrdup("");
} else {
- (*ps) = smb_xstrdup("");
+ if (len1 != len2 || ptr + len1 > blob->length) {
+ return False;
+ }
+
+ if (0 < len1) {
+ pull_string(NULL, p, blob->data + ptr, sizeof(p),
+ len1,
+ STR_ASCII|STR_NOALIGN);
+ (*ps) = smb_xstrdup(p);
+ } else {
+ (*ps) = smb_xstrdup("");
+ }
}
break;
case 'B':
@@ -265,12 +273,17 @@ BOOL msrpc_parse(const DATA_BLOB *blob,
len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
- /* make sure its in the right format - be strict */
- if (len1 != len2 || ptr + len1 > blob->length) {
- return False;
- }
+
b = (DATA_BLOB *)va_arg(ap, void *);
- *b = data_blob(blob->data + ptr, len1);
+ if (len1 == 0 && len2 == 0) {
+ *b = data_blob(NULL, 0);
+ } else {
+ /* make sure its in the right format - be strict */
+ if (len1 != len2 || ptr + len1 > blob->length) {
+ return False;
+ }
+ *b = data_blob(blob->data + ptr, len1);
+ }
break;
case 'b':
b = (DATA_BLOB *)va_arg(ap, void *);
diff --git a/source3/libsmb/ntlmssp_sign.c b/source3/libsmb/ntlmssp_sign.c
index 86faf1f5e6..748c008963 100644
--- a/source3/libsmb/ntlmssp_sign.c
+++ b/source3/libsmb/ntlmssp_sign.c
@@ -79,13 +79,18 @@ static void calc_hash(unsigned char *hash, const char *k2, int k2l)
}
static void calc_ntlmv2_hash(unsigned char hash[16], char digest[16],
- const char encrypted_response[16],
+ DATA_BLOB session_key,
const char *constant)
{
struct MD5Context ctx3;
+ /* NOTE: This code is currently complate fantasy - it's
+ got more in common with reality than the previous code
+ (the LM session key is not the right thing to use) but
+ it still needs work */
+
MD5Init(&ctx3);
- MD5Update(&ctx3, encrypted_response, 5);
+ MD5Update(&ctx3, session_key.data, session_key.length);
MD5Update(&ctx3, constant, strlen(constant));
MD5Final(digest, &ctx3);
@@ -113,25 +118,28 @@ static NTSTATUS ntlmssp_make_packet_signiture(NTLMSSP_CLIENT_STATE *ntlmssp_stat
hmac_md5_update(data, length, &ctx);
hmac_md5_final(digest, &ctx);
- if (!msrpc_gen(sig, "Bd", digest, sizeof(digest), ntlmssp_state->ntlmssp_seq_num)) {
+ if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */
+ , ntlmssp_state->ntlmssp_seq_num)) {
return NT_STATUS_NO_MEMORY;
}
switch (direction) {
case NTLMSSP_SEND:
- NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash, sig->data, sig->length);
+ NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash, sig->data+4, sig->length-4);
break;
case NTLMSSP_RECEIVE:
- NTLMSSPcalc_ap(ntlmssp_state->srv_sign_hash, sig->data, sig->length);
+ NTLMSSPcalc_ap(ntlmssp_state->srv_sign_hash, sig->data+4, sig->length-4);
break;
}
} else {
uint32 crc;
crc = crc32_calc_buffer(data, length);
- if (!msrpc_gen(sig, "ddd", 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+ if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
return NT_STATUS_NO_MEMORY;
}
- NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data, sig->length);
+ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
}
return NT_STATUS_OK;
}
@@ -140,8 +148,11 @@ NTSTATUS ntlmssp_client_sign_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
const uchar *data, size_t length,
DATA_BLOB *sig)
{
+ NTSTATUS nt_status = ntlmssp_make_packet_signiture(ntlmssp_state, data, length, NTLMSSP_SEND, sig);
+
+ /* increment counter on send */
ntlmssp_state->ntlmssp_seq_num++;
- return ntlmssp_make_packet_signiture(ntlmssp_state, data, length, NTLMSSP_SEND, sig);
+ return nt_status;
}
/**
@@ -151,8 +162,8 @@ NTSTATUS ntlmssp_client_sign_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
*/
NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
- const uchar *data, size_t length,
- const DATA_BLOB *sig)
+ const uchar *data, size_t length,
+ const DATA_BLOB *sig)
{
DATA_BLOB local_sig;
NTSTATUS nt_status;
@@ -170,9 +181,7 @@ NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
return nt_status;
}
- if (memcmp(sig->data, local_sig.data, MIN(sig->length, local_sig.length)) == 0) {
- return NT_STATUS_OK;
- } else {
+ if (memcmp(sig->data+sig->length - 8, local_sig.data+local_sig.length - 8, 8) != 0) {
DEBUG(5, ("BAD SIG: wanted signature of\n"));
dump_data(5, local_sig.data, local_sig.length);
@@ -182,6 +191,97 @@ NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
DEBUG(0, ("NTLMSSP packet check failed due to invalid signiture!\n"));
return NT_STATUS_ACCESS_DENIED;
}
+
+ /* increment counter on recieive */
+ ntlmssp_state->ntlmssp_seq_num++;
+
+ return NT_STATUS_OK;
+}
+
+
+/**
+ * Seal data with the NTLMSSP algorithm
+ *
+ */
+
+NTSTATUS ntlmssp_client_seal_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+ uchar *data, size_t length,
+ DATA_BLOB *sig)
+{
+ DEBUG(10,("ntlmssp_client_seal_data: seal\n"));
+ dump_data_pw("ntlmssp clear data\n", data, length);
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ HMACMD5Context ctx;
+ char seq_num[4];
+ uchar digest[16];
+ SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
+
+ hmac_md5_init_limK_to_64(ntlmssp_state->cli_sign_const, 16, &ctx);
+ hmac_md5_update(seq_num, 4, &ctx);
+ hmac_md5_update(data, length, &ctx);
+ hmac_md5_final(digest, &ctx);
+
+ if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */
+ , ntlmssp_state->ntlmssp_seq_num)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ dump_data_pw("ntlmssp client sealing hash:\n",
+ ntlmssp_state->cli_seal_hash,
+ sizeof(ntlmssp_state->cli_seal_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->cli_seal_hash, data, length);
+ dump_data_pw("ntlmssp client signing hash:\n",
+ ntlmssp_state->cli_sign_hash,
+ sizeof(ntlmssp_state->cli_sign_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash, sig->data+4, sig->length-4);
+ } else {
+ uint32 crc;
+ crc = crc32_calc_buffer(data, length);
+ if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* The order of these two operations matters - we must first seal the packet,
+ then seal the sequence number - this is becouse the ntlmssp_hash is not
+ constant, but is is rather updated with each iteration */
+
+ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length);
+
+ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
+ }
+ dump_data_pw("ntlmssp sealed data\n", data, length);
+
+ /* increment counter on send */
+ ntlmssp_state->ntlmssp_seq_num++;
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * Unseal data with the NTLMSSP algorithm
+ *
+ */
+
+NTSTATUS ntlmssp_client_unseal_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+ uchar *data, size_t length,
+ DATA_BLOB *sig)
+{
+ DEBUG(10,("ntlmssp_client_unseal_data: seal\n"));
+ dump_data_pw("ntlmssp sealed data\n", data, length);
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ NTLMSSPcalc_ap(ntlmssp_state->srv_seal_hash, data, length);
+ } else {
+ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length);
+ }
+ dump_data_pw("ntlmssp clear data\n", data, length);
+
+ return ntlmssp_client_check_packet(ntlmssp_state, data, length, sig);
}
/**
@@ -190,37 +290,69 @@ NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
NTSTATUS ntlmssp_client_sign_init(NTLMSSP_CLIENT_STATE *ntlmssp_state)
{
unsigned char p24[24];
- unsigned char lm_hash[16];
+ ZERO_STRUCT(p24);
+
+ DEBUG(3, ("NTLMSSP Sign/Seal - Initialising with flags:\n"));
+ debug_ntlmssp_flags(ntlmssp_state->neg_flags);
- if (!ntlmssp_state->lm_resp.data) {
- /* can't sign or check signitures yet */
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- E_deshash(ntlmssp_state->password, lm_hash);
-
- NTLMSSPOWFencrypt(lm_hash, ntlmssp_state->lm_resp.data, p24);
-
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
{
- calc_ntlmv2_hash(ntlmssp_state->cli_sign_hash, ntlmssp_state->cli_sign_const, p24, CLI_SIGN);
- calc_ntlmv2_hash(ntlmssp_state->cli_seal_hash, ntlmssp_state->cli_seal_const, p24, CLI_SEAL);
- calc_ntlmv2_hash(ntlmssp_state->srv_sign_hash, ntlmssp_state->srv_sign_const, p24, SRV_SIGN);
- calc_ntlmv2_hash(ntlmssp_state->srv_seal_hash, ntlmssp_state->srv_seal_const, p24, SRV_SEAL);
- }
- else
- {
- char k2[8];
- memcpy(k2, p24, 5);
- k2[5] = 0xe5;
- k2[6] = 0x38;
- k2[7] = 0xb0;
+
+ calc_ntlmv2_hash(ntlmssp_state->cli_sign_hash,
+ ntlmssp_state->cli_sign_const,
+ ntlmssp_state->session_key, CLI_SIGN);
+ dump_data_pw("NTLMSSP client sign hash:\n",
+ ntlmssp_state->cli_sign_hash,
+ sizeof(ntlmssp_state->cli_sign_hash));
+
+ calc_ntlmv2_hash(ntlmssp_state->cli_seal_hash,
+ ntlmssp_state->cli_seal_const,
+ ntlmssp_state->session_key, CLI_SEAL);
+ dump_data_pw("NTLMSSP client sesl hash:\n",
+ ntlmssp_state->cli_seal_hash,
+ sizeof(ntlmssp_state->cli_seal_hash));
+
+ calc_ntlmv2_hash(ntlmssp_state->srv_sign_hash,
+ ntlmssp_state->srv_sign_const,
+ ntlmssp_state->session_key, SRV_SIGN);
+ dump_data_pw("NTLMSSP server sign hash:\n",
+ ntlmssp_state->srv_sign_hash,
+ sizeof(ntlmssp_state->srv_sign_hash));
+
+ calc_ntlmv2_hash(ntlmssp_state->srv_seal_hash,
+ ntlmssp_state->srv_seal_const,
+ ntlmssp_state->session_key, SRV_SEAL);
+ dump_data_pw("NTLMSSP server seal hash:\n",
+ ntlmssp_state->cli_sign_hash,
+ sizeof(ntlmssp_state->cli_sign_hash));
+ }
+ else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) {
+ if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 8) {
+ /* can't sign or check signitures yet */
+ DEBUG(5, ("NTLMSSP Sign/Seal - cannot use LM KEY yet\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(5, ("NTLMSSP Sign/Seal - using LM KEY\n"));
+
+ calc_hash(ntlmssp_state->ntlmssp_hash, ntlmssp_state->session_key.data, 8);
+ dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ } else {
+ if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 16) {
+ /* can't sign or check signitures yet */
+ DEBUG(5, ("NTLMSSP Sign/Seal - cannot use NT KEY yet\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
- calc_hash(ntlmssp_state->ntlmssp_hash, k2, 8);
+ DEBUG(5, ("NTLMSSP Sign/Seal - using NT KEY\n"));
+
+ calc_hash(ntlmssp_state->ntlmssp_hash, ntlmssp_state->session_key.data, 16);
+ dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
}
ntlmssp_state->ntlmssp_seq_num = 0;
- ZERO_STRUCT(lm_hash);
return NT_STATUS_OK;
}
diff --git a/source3/libsmb/pwd_cache.c b/source3/libsmb/pwd_cache.c
index 7ddcf853c4..f45832d7d7 100644
--- a/source3/libsmb/pwd_cache.c
+++ b/source3/libsmb/pwd_cache.c
@@ -43,15 +43,10 @@ static void pwd_init(struct pwd_info *pwd)
static void pwd_make_lm_nt_16(struct pwd_info *pwd, const char *clr)
{
- pstring dos_passwd;
-
pwd_init(pwd);
- push_ascii_pstring(dos_passwd, clr);
-
- nt_lm_owf_gen(dos_passwd, pwd->smb_nt_pwd, pwd->smb_lm_pwd);
+ nt_lm_owf_gen(clr, pwd->smb_nt_pwd, pwd->smb_lm_pwd);
pwd->null_pwd = False;
- pwd->cleartext = False;
pwd->crypted = False;
}
@@ -61,12 +56,9 @@ static void pwd_make_lm_nt_16(struct pwd_info *pwd, const char *clr)
void pwd_set_cleartext(struct pwd_info *pwd, const char *clr)
{
- pwd_init(pwd);
- push_ascii_fstring(pwd->password, clr);
- pwd->cleartext = True;
- pwd->null_pwd = False;
- pwd->crypted = False;
pwd_make_lm_nt_16(pwd, clr);
+ fstrcpy(pwd->password, clr);
+ pwd->cleartext = True;
}
/****************************************************************************
diff --git a/source3/libsmb/smbencrypt.c b/source3/libsmb/smbencrypt.c
index c1b3880299..7a1a2d7d18 100644
--- a/source3/libsmb/smbencrypt.c
+++ b/source3/libsmb/smbencrypt.c
@@ -271,6 +271,8 @@ void SMBOWFencrypt_ntv2(const uchar kr[16],
void SMBsesskeygen_ntv2(const uchar kr[16],
const uchar * nt_resp, uint8 sess_key[16])
{
+ /* a very nice, 128 bit, variable session key */
+
HMACMD5Context ctx;
hmac_md5_init_limK_to_64(kr, 16, &ctx);
@@ -286,6 +288,9 @@ void SMBsesskeygen_ntv2(const uchar kr[16],
void SMBsesskeygen_ntv1(const uchar kr[16],
const uchar * nt_resp, uint8 sess_key[16])
{
+ /* yes, this session key does not change - yes, this
+ is a problem - but it is 128 bits */
+
mdfour((unsigned char *)sess_key, kr, 16);
#ifdef DEBUG_PASSWORD
@@ -294,6 +299,32 @@ void SMBsesskeygen_ntv1(const uchar kr[16],
#endif
}
+void SMBsesskeygen_lmv1(const uchar lm_hash[16],
+ const uchar lm_resp[24], /* only uses 8 */
+ uint8 sess_key[16])
+{
+ /* Calculate the LM session key (effective length 40 bits,
+ but changes with each session) */
+
+ uchar p24[24];
+ uchar partial_lm_hash[16];
+
+ memcpy(partial_lm_hash, lm_hash, 8);
+ memset(partial_lm_hash + 8, 0xbd, 8);
+
+ SMBOWFencrypt(lm_hash, lm_resp, p24);
+
+ memcpy(sess_key, p24, 16);
+ sess_key[5] = 0xe5;
+ sess_key[6] = 0x38;
+ sess_key[7] = 0xb0;
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBsesskeygen_lmv1:\n"));
+ dump_data(100, sess_key, 16);
+#endif
+}
+
DATA_BLOB NTLMv2_generate_names_blob(const char *hostname,
const char *domain)
{