summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/ntlmssp.h19
-rw-r--r--source3/libsmb/asn1.c21
-rw-r--r--source3/libsmb/cliconnect.c179
-rw-r--r--source3/libsmb/clispnego.c56
-rw-r--r--source3/libsmb/errormap.c2
-rw-r--r--source3/libsmb/ntlmssp.c304
-rw-r--r--source3/libsmb/ntlmssp_parse.c6
7 files changed, 459 insertions, 128 deletions
diff --git a/source3/include/ntlmssp.h b/source3/include/ntlmssp.h
index 9a79707238..4fa4259a6a 100644
--- a/source3/include/ntlmssp.h
+++ b/source3/include/ntlmssp.h
@@ -89,3 +89,22 @@ typedef struct ntlmssp_state
uint32 expected_state;
} NTLMSSP_STATE;
+typedef struct ntlmssp_client_state
+{
+ TALLOC_CTX *mem_ctx;
+ BOOL unicode;
+ BOOL use_ntlmv2;
+ char *user;
+ char *domain;
+ char *workstation;
+ char *password;
+
+ const char *(*get_global_myname)(void);
+ const char *(*get_domain)(void);
+
+ DATA_BLOB session_key;
+
+ uint32 neg_flags;
+
+} NTLMSSP_CLIENT_STATE;
+
diff --git a/source3/libsmb/asn1.c b/source3/libsmb/asn1.c
index 333d157905..09d4fbb6c9 100644
--- a/source3/libsmb/asn1.c
+++ b/source3/libsmb/asn1.c
@@ -240,7 +240,9 @@ BOOL asn1_start_tag(ASN1_DATA *data, uint8 tag)
uint8 b;
struct nesting *nesting;
- asn1_read_uint8(data, &b);
+ if (!asn1_read_uint8(data, &b))
+ return False;
+
if (b != tag) {
data->has_error = True;
return False;
@@ -251,13 +253,18 @@ BOOL asn1_start_tag(ASN1_DATA *data, uint8 tag)
return False;
}
- asn1_read_uint8(data, &b);
+ if (!asn1_read_uint8(data, &b)) {
+ return False;
+ }
+
if (b & 0x80) {
int n = b & 0x7f;
- asn1_read_uint8(data, &b);
+ if (!asn1_read_uint8(data, &b))
+ return False;
nesting->taglen = b;
while (n > 1) {
- asn1_read_uint8(data, &b);
+ if (!asn1_read_uint8(data, &b))
+ return False;
nesting->taglen = (nesting->taglen << 8) | b;
n--;
}
@@ -404,7 +411,11 @@ BOOL asn1_check_enumerated(ASN1_DATA *data, int v)
if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
asn1_read_uint8(data, &b);
asn1_end_tag(data);
- return !data->has_error && (v == b);
+
+ if (v != b)
+ data->has_error = False;
+
+ return !data->has_error;
}
/* write an enumarted value to the stream */
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index 90a7eca8e7..2b0b9abc9d 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -385,11 +385,9 @@ static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
{
uint32 capabilities = cli_session_setup_capabilities(cli);
char *p;
- DATA_BLOB blob2;
+ DATA_BLOB blob2 = data_blob(NULL, 0);
uint32 len;
- blob2 = data_blob(NULL, 0);
-
capabilities |= CAP_EXTENDED_SECURITY;
/* send a session setup command */
@@ -449,7 +447,7 @@ static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
Use in-memory credentials cache
****************************************************************************/
static void use_in_memory_ccache() {
- setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads_testjoin", 1);
+ setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
}
/****************************************************************************
@@ -489,128 +487,83 @@ static BOOL cli_session_setup_kerberos(struct cli_state *cli, const char *princi
static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
const char *pass, const char *workgroup)
{
- DATA_BLOB msg1, struct_blob;
- DATA_BLOB blob, chal1, chal2, auth, challenge_blob;
- uint8 challenge[8];
- uint8 nthash[24], lmhash[24], sess_key[16];
- uint32 neg_flags, chal_flags, ntlmssp_command, unkn1, unkn2;
- pstring server_domain; /* FIX THIS, SHOULD be UCS2-LE */
-
- neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
- NTLMSSP_NEGOTIATE_128 |
- NTLMSSP_NEGOTIATE_NTLM |
- NTLMSSP_REQUEST_TARGET;
-
- memset(sess_key, 0, 16);
-
- DEBUG(10, ("sending NTLMSSP_NEGOTIATE\n"));
-
- /* generate the ntlmssp negotiate packet */
- msrpc_gen(&blob, "CddAA",
- "NTLMSSP",
- NTLMSSP_NEGOTIATE,
- neg_flags,
- workgroup,
- cli->calling.name);
- DEBUG(10, ("neg_flags: %0X, workgroup: %s, calling name %s\n",
- neg_flags, workgroup, cli->calling.name));
- /* and wrap it in a SPNEGO wrapper */
- msg1 = gen_negTokenInit(OID_NTLMSSP, blob);
- data_blob_free(&blob);
-
- /* now send that blob on its way */
- blob = cli_session_setup_blob(cli, msg1);
-
- data_blob_free(&msg1);
-
- if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED))
- return False;
-
-#if 0
- file_save("chal.dat", blob.data, blob.length);
-#endif
+ struct ntlmssp_client_state *ntlmssp_state;
+ NTSTATUS nt_status;
+ int turn = 1;
+ DATA_BLOB msg1;
+ DATA_BLOB blob;
+ DATA_BLOB blob_in = data_blob(NULL, 0);
+ DATA_BLOB blob_out;
- /* the server gives us back two challenges */
- if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
- DEBUG(3,("Failed to parse challenges\n"));
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
return False;
}
- data_blob_free(&blob);
-
- /*
- * Ok, chal1 and chal2 are actually two identical copies of
- * the NTLMSSP Challenge BLOB, and they contain, encoded in them
- * the challenge to use.
- */
-
- if (!msrpc_parse(&chal1, "CdUdbddB",
- "NTLMSSP",
- &ntlmssp_command,
- &server_domain,
- &chal_flags,
- &challenge_blob, 8,
- &unkn1, &unkn2,
- &struct_blob)) {
- DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
- return False;
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) {
+ return False;
}
-
- if (ntlmssp_command != NTLMSSP_CHALLENGE) {
- DEBUG(0, ("NTLMSSP Response != NTLMSSP_CHALLENGE. Got %0X\n",
- ntlmssp_command));
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, workgroup))) {
return False;
}
-
- if (challenge_blob.length < 8) {
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, pass))) {
return False;
}
- DEBUG(10, ("Challenge:\n"));
- dump_data(10, challenge_blob.data, 8);
-
- /* encrypt the password with the challenge which is in the blob */
- memcpy(challenge, challenge_blob.data, 8);
- SMBencrypt(pass, challenge,lmhash);
- SMBNTencrypt(pass, challenge,nthash);
- data_blob_free(&challenge_blob);
-
-#if 0
- file_save("nthash.dat", nthash, 24);
- file_save("lmhash.dat", lmhash, 24);
- file_save("chal1.dat", chal1.data, chal1.length);
-#endif
-
- data_blob_free(&chal1);
- data_blob_free(&chal2);
-
- /* this generates the actual auth packet */
- msrpc_gen(&blob, "CdBBUUUBd",
- "NTLMSSP",
- NTLMSSP_AUTH,
- lmhash, 24,
- nthash, 24,
- workgroup,
- user,
- cli->calling.name,
- sess_key, 0,
- neg_flags);
-
- /* wrap it in SPNEGO */
- auth = spnego_gen_auth(blob);
-
- data_blob_free(&blob);
-
- /* now send the auth packet and we should be done */
- blob = cli_session_setup_blob(cli, auth);
-
- data_blob_free(&auth);
- data_blob_free(&blob);
+ ntlmssp_state->use_ntlmv2 = lp_client_ntlmv2_auth();
+
+ do {
+ nt_status = ntlmssp_client_update(ntlmssp_state,
+ blob_in, &blob_out);
+ data_blob_free(&blob_in);
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ if (turn == 1) {
+ /* and wrap it in a SPNEGO wrapper */
+ msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
+ } else {
+ /* wrap it in SPNEGO */
+ msg1 = spnego_gen_auth(blob_out);
+ }
+
+ /* now send that blob on its way */
+ blob = cli_session_setup_blob(cli, msg1);
+ data_blob_free(&msg1);
+ nt_status = cli_nt_error(cli);
+ }
+
+ if (!blob.length) {
+ if (NT_STATUS_IS_OK(nt_status)) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ }
+ } else if ((turn == 1) &&
+ NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ DATA_BLOB tmp_blob = data_blob(NULL, 0);
+ /* the server might give us back two challenges */
+ if (!spnego_parse_challenge(blob, &blob_in,
+ &tmp_blob)) {
+ DEBUG(3,("Failed to parse challenges\n"));
+ nt_status = NT_STATUS_INVALID_PARAMETER;
+ }
+ data_blob_free(&tmp_blob);
+ } else {
+ /* the server might give us back two challenges */
+ if (!spnego_parse_auth_response(blob, nt_status,
+ &blob_in)) {
+ DEBUG(3,("Failed to parse auth response\n"));
+ if (NT_STATUS_IS_OK(nt_status)
+ || NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED))
+ nt_status = NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+ data_blob_free(&blob);
+ data_blob_free(&blob_out);
+ turn++;
+ } while (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED));
- if (cli_is_error(cli))
+ if (!NT_STATUS_IS_OK(ntlmssp_client_end(&ntlmssp_state))) {
return False;
+ }
- return True;
+ return (NT_STATUS_IS_OK(nt_status));
}
/****************************************************************************
diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c
index 91748c4c7a..e93f1855dd 100644
--- a/source3/libsmb/clispnego.c
+++ b/source3/libsmb/clispnego.c
@@ -345,7 +345,7 @@ DATA_BLOB spnego_gen_negTokenTarg(const char *principal, int time_offset)
/*
parse a spnego NTLMSSP challenge packet giving two security blobs
*/
-BOOL spnego_parse_challenge(DATA_BLOB blob,
+BOOL spnego_parse_challenge(const DATA_BLOB blob,
DATA_BLOB *chal1, DATA_BLOB *chal2)
{
BOOL ret;
@@ -387,7 +387,7 @@ BOOL spnego_parse_challenge(DATA_BLOB blob,
/*
- generate a SPNEGO NTLMSSP auth packet. This will contain the encrypted passwords
+ generate a SPNEGO auth packet. This will contain the encrypted passwords
*/
DATA_BLOB spnego_gen_auth(DATA_BLOB blob)
{
@@ -412,7 +412,7 @@ DATA_BLOB spnego_gen_auth(DATA_BLOB blob)
}
/*
- parse a SPNEGO NTLMSSP auth packet. This contains the encrypted passwords
+ parse a SPNEGO auth packet. This contains the encrypted passwords
*/
BOOL spnego_parse_auth(DATA_BLOB blob, DATA_BLOB *auth)
{
@@ -461,6 +461,7 @@ DATA_BLOB spnego_gen_auth_response(DATA_BLOB *ntlmssp_reply, NTSTATUS nt_status)
asn1_push_tag(&data, ASN1_CONTEXT(0));
asn1_write_enumerated(&data, negResult);
asn1_pop_tag(&data);
+
if (negResult == SPNEGO_NEG_RESULT_INCOMPLETE) {
asn1_push_tag(&data,ASN1_CONTEXT(1));
asn1_write_OID(&data, OID_NTLMSSP);
@@ -478,3 +479,52 @@ DATA_BLOB spnego_gen_auth_response(DATA_BLOB *ntlmssp_reply, NTSTATUS nt_status)
asn1_free(&data);
return ret;
}
+
+/*
+ parse a SPNEGO NTLMSSP auth packet. This contains the encrypted passwords
+*/
+BOOL spnego_parse_auth_response(DATA_BLOB blob, NTSTATUS nt_status,
+ DATA_BLOB *auth)
+{
+ ASN1_DATA data;
+ uint8 negResult;
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ negResult = SPNEGO_NEG_RESULT_ACCEPT;
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ negResult = SPNEGO_NEG_RESULT_INCOMPLETE;
+ } else {
+ negResult = SPNEGO_NEG_RESULT_REJECT;
+ }
+
+ asn1_load(&data, blob);
+ asn1_start_tag(&data, ASN1_CONTEXT(1));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_start_tag(&data, ASN1_CONTEXT(0));
+ asn1_check_enumerated(&data, negResult);
+ asn1_end_tag(&data);
+
+ if (negResult == SPNEGO_NEG_RESULT_INCOMPLETE) {
+ asn1_start_tag(&data,ASN1_CONTEXT(1));
+ asn1_check_OID(&data, OID_NTLMSSP);
+ asn1_end_tag(&data);
+
+ asn1_start_tag(&data,ASN1_CONTEXT(2));
+ asn1_read_OctetString(&data, auth);
+ asn1_end_tag(&data);
+ }
+
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(3,("spnego_parse_auth_response failed at %d\n", (int)data.ofs));
+ asn1_free(&data);
+ data_blob_free(auth);
+ return False;
+ }
+
+ asn1_free(&data);
+ return True;
+}
+
diff --git a/source3/libsmb/errormap.c b/source3/libsmb/errormap.c
index 09340caccd..8ee5ee3d31 100644
--- a/source3/libsmb/errormap.c
+++ b/source3/libsmb/errormap.c
@@ -1410,7 +1410,7 @@ static const struct {
/*****************************************************************************
convert a dos eclas/ecode to a NT status32 code
*****************************************************************************/
-NTSTATUS dos_to_ntstatus(int eclass, int ecode)
+NTSTATUS dos_to_ntstatus(uint8 eclass, uint32 ecode)
{
int i;
if (eclass == 0 && ecode == 0) return NT_STATUS_OK;
diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c
index 92a18d25c0..7992c1e84a 100644
--- a/source3/libsmb/ntlmssp.c
+++ b/source3/libsmb/ntlmssp.c
@@ -25,6 +25,7 @@
/**
* Print out the NTLMSSP flags for debugging
+ * @param neg_flags The flags from the packet
*/
void debug_ntlmssp_flags(uint32 neg_flags)
@@ -78,6 +79,16 @@ static const uint8 *get_challenge(struct ntlmssp_state *ntlmssp_state)
return chal;
}
+/**
+ * Determine correct target name flags for reply, given server role
+ * and negoitated falgs
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param neg_flags The flags from the packet
+ * @param chal_flags The flags to be set in the reply packet
+ * @return The 'target name' string.
+ */
+
static const char *ntlmssp_target_name(struct ntlmssp_state *ntlmssp_state,
uint32 neg_flags, uint32 *chal_flags)
{
@@ -96,8 +107,17 @@ static const char *ntlmssp_target_name(struct ntlmssp_state *ntlmssp_state,
}
}
+/**
+ * Next state function for the Negotiate packet
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB
+ * @param request The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors or MORE_PROCESSING_REQUIRED if a reply is sent.
+ */
+
static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
- DATA_BLOB request, DATA_BLOB *reply)
+ const DATA_BLOB request, DATA_BLOB *reply)
{
DATA_BLOB struct_blob;
fstring dnsname, dnsdomname;
@@ -201,8 +221,17 @@ static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
return NT_STATUS_MORE_PROCESSING_REQUIRED;
}
+/**
+ * Next state function for the Authenticate packet
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB
+ * @param request The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors or NT_STATUS_OK.
+ */
+
static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
- DATA_BLOB request, DATA_BLOB *reply)
+ const DATA_BLOB request, DATA_BLOB *reply)
{
DATA_BLOB sess_key;
uint32 ntlmssp_command, neg_flags;
@@ -259,6 +288,12 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
return nt_status;
}
+/**
+ * Create an NTLMSSP state machine
+ *
+ * @param ntlmssp_state NTLMSSP State, allocated by this funciton
+ */
+
NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
{
TALLOC_CTX *mem_ctx;
@@ -286,6 +321,12 @@ NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
return NT_STATUS_OK;
}
+/**
+ * End an NTLMSSP state machine
+ *
+ * @param ntlmssp_state NTLMSSP State, free()ed by this funciton
+ */
+
NTSTATUS ntlmssp_server_end(NTLMSSP_STATE **ntlmssp_state)
{
TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
@@ -303,8 +344,17 @@ NTSTATUS ntlmssp_server_end(NTLMSSP_STATE **ntlmssp_state)
return NT_STATUS_OK;
}
+/**
+ * Next state function for the NTLMSSP state machine
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB
+ * @param request The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors, NT_STATUS_MORE_PROCESSING_REQUIRED or NT_STATUS_OK.
+ */
+
NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state,
- DATA_BLOB request, DATA_BLOB *reply)
+ const DATA_BLOB request, DATA_BLOB *reply)
{
uint32 ntlmssp_command;
*reply = data_blob(NULL, 0);
@@ -328,3 +378,251 @@ NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state,
}
}
+/*********************************************************************
+ Client side NTLMSSP
+*********************************************************************/
+
+/**
+ * Next state function for the Initial packet
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB. reply.data must be NULL
+ * @param request The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors or NT_STATUS_OK.
+ */
+
+static NTSTATUS ntlmssp_client_initial(struct ntlmssp_client_state *ntlmssp_state,
+ DATA_BLOB reply, DATA_BLOB *next_request)
+{
+ if (ntlmssp_state->unicode) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
+ }
+
+ /* generate the ntlmssp negotiate packet */
+ msrpc_gen(next_request, "CddAA",
+ "NTLMSSP",
+ NTLMSSP_NEGOTIATE,
+ ntlmssp_state->neg_flags,
+ ntlmssp_state->get_domain(),
+ ntlmssp_state->get_global_myname());
+
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+/**
+ * Next state function for the Challenge Packet. Generate an auth packet.
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB. reply.data must be NULL
+ * @param request The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors or NT_STATUS_OK.
+ */
+
+static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_state,
+ const DATA_BLOB reply, DATA_BLOB *next_request)
+{
+ uint32 chal_flags, ntlmssp_command, unkn1, unkn2;
+ DATA_BLOB server_domain_blob;
+ DATA_BLOB challenge_blob;
+ DATA_BLOB struct_blob;
+ char *server_domain;
+ const char *chal_parse_string;
+ const char *auth_gen_string;
+ DATA_BLOB lm_response = data_blob(NULL, 0);
+ DATA_BLOB nt_response = data_blob(NULL, 0);
+ DATA_BLOB session_key = data_blob(NULL, 0);
+ uint8 datagram_sess_key[16];
+
+ ZERO_STRUCT(datagram_sess_key);
+
+ if (!msrpc_parse(&reply, "CdBd",
+ "NTLMSSP",
+ &ntlmssp_command,
+ &server_domain_blob,
+ &chal_flags)) {
+ DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ data_blob_free(&server_domain_blob);
+
+ if (chal_flags & NTLMSSP_NEGOTIATE_UNICODE) {
+ chal_parse_string = "CdUdbddB";
+ 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";
+ auth_gen_string = "CdBBAAABd";
+ ntlmssp_state->unicode = False;
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE;
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
+ } else {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!msrpc_parse(&reply, chal_parse_string,
+ "NTLMSSP",
+ &ntlmssp_command,
+ &server_domain,
+ &chal_flags,
+ &challenge_blob, 8,
+ &unkn1, &unkn2,
+ &struct_blob)) {
+ DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ SAFE_FREE(server_domain);
+ data_blob_free(&struct_blob);
+
+ if (challenge_blob.length != 8) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (ntlmssp_state->use_ntlmv2) {
+
+ /* TODO: if the remote server is standalone, then we should replace 'domain'
+ with the server name as supplied above */
+
+ if (!SMBNTLMv2encrypt(ntlmssp_state->user,
+ ntlmssp_state->domain,
+ ntlmssp_state->password, challenge_blob,
+ &lm_response, &nt_response, &session_key)) {
+ data_blob_free(&challenge_blob);
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ uchar nt_hash[16];
+ E_md4hash(ntlmssp_state->password, nt_hash);
+
+ /* non encrypted password supplied. Ignore ntpass. */
+ if (lp_client_lanman_auth()) {
+ lm_response = data_blob(NULL, 24);
+ SMBencrypt(ntlmssp_state->password,challenge_blob.data,
+ lm_response.data);
+ }
+
+ 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);
+ }
+
+ data_blob_free(&challenge_blob);
+
+ /* this generates the actual auth packet */
+ if (!msrpc_gen(next_request, auth_gen_string,
+ "NTLMSSP",
+ NTLMSSP_AUTH,
+ lm_response.data, lm_response.length,
+ nt_response.data, nt_response.length,
+ ntlmssp_state->domain,
+ ntlmssp_state->user,
+ ntlmssp_state->get_global_myname(),
+ datagram_sess_key, 0,
+ ntlmssp_state->neg_flags)) {
+
+ data_blob_free(&lm_response);
+ data_blob_free(&nt_response);
+ data_blob_free(&session_key);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ data_blob_free(&lm_response);
+ data_blob_free(&nt_response);
+
+ ntlmssp_state->session_key = session_key;
+
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS ntlmssp_client_start(NTLMSSP_CLIENT_STATE **ntlmssp_state)
+{
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("NTLMSSP Client context");
+
+ *ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state));
+ if (!*ntlmssp_state) {
+ DEBUG(0,("ntlmssp_server_start: talloc failed!\n"));
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCTP(*ntlmssp_state);
+
+ (*ntlmssp_state)->mem_ctx = mem_ctx;
+
+ (*ntlmssp_state)->get_global_myname = global_myname;
+ (*ntlmssp_state)->get_domain = lp_workgroup;
+
+ (*ntlmssp_state)->unicode = True;
+
+ (*ntlmssp_state)->neg_flags =
+ NTLMSSP_NEGOTIATE_128 |
+ NTLMSSP_NEGOTIATE_NTLM |
+ NTLMSSP_REQUEST_TARGET;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS ntlmssp_client_end(NTLMSSP_CLIENT_STATE **ntlmssp_state)
+{
+ TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
+
+ talloc_destroy(mem_ctx);
+ *ntlmssp_state = NULL;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS ntlmssp_client_update(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+ DATA_BLOB reply, DATA_BLOB *next_request)
+{
+ uint32 ntlmssp_command;
+ *next_request = data_blob(NULL, 0);
+
+ if (!reply.length) {
+ return ntlmssp_client_initial(ntlmssp_state, reply, next_request);
+ }
+
+ if (!msrpc_parse(&reply, "Cd",
+ "NTLMSSP",
+ &ntlmssp_command)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (ntlmssp_command == NTLMSSP_CHALLENGE) {
+ return ntlmssp_client_challenge(ntlmssp_state, reply, next_request);
+ }
+ return NT_STATUS_INVALID_PARAMETER;
+}
+
+NTSTATUS ntlmssp_set_username(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *user)
+{
+ ntlmssp_state->user = talloc_strdup(ntlmssp_state->mem_ctx, user);
+ if (!ntlmssp_state->user) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS ntlmssp_set_password(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *password)
+{
+ ntlmssp_state->password = talloc_strdup(ntlmssp_state->mem_ctx, password);
+ if (!ntlmssp_state->password) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS ntlmssp_set_domain(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *domain)
+{
+ ntlmssp_state->domain = talloc_strdup(ntlmssp_state->mem_ctx, domain);
+ if (!ntlmssp_state->domain) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
diff --git a/source3/libsmb/ntlmssp_parse.c b/source3/libsmb/ntlmssp_parse.c
index 5f3132694e..6644a3db71 100644
--- a/source3/libsmb/ntlmssp_parse.c
+++ b/source3/libsmb/ntlmssp_parse.c
@@ -181,7 +181,7 @@ BOOL msrpc_gen(DATA_BLOB *blob,
/* a helpful macro to avoid running over the end of our blob */
#define NEED_DATA(amount) \
-if (head_ofs + amount > blob->length) { \
+if ((head_ofs + amount) > blob->length) { \
return False; \
}
@@ -198,14 +198,14 @@ if (head_ofs + amount > blob->length) { \
C = constant ascii string
*/
-BOOL msrpc_parse(DATA_BLOB *blob,
+BOOL msrpc_parse(const DATA_BLOB *blob,
const char *format, ...)
{
int i;
va_list ap;
char **ps, *s;
DATA_BLOB *b;
- int head_ofs = 0;
+ size_t head_ofs = 0;
uint16 len1, len2;
uint32 ptr;
uint32 *v;