Move our NTLMSSP client code into ntlmssp.c. The intention is to provide a
authorAndrew Bartlett <abartlet@samba.org>
Sat, 15 Feb 2003 12:20:22 +0000 (12:20 +0000)
committerAndrew Bartlett <abartlet@samba.org>
Sat, 15 Feb 2003 12:20:22 +0000 (12:20 +0000)
relitivly useful external lib from this code, and to remove the dupicate
NTLMSSP code elsewhere in samba (RPC pipes, LDAP client).

The code I've replaced this with in cliconnect.c is relitivly ugly, and
I hope to replace it with a more general SPENGO layer at some later date.

Andrew Bartlett
(This used to be commit b2b66909ac2e251f8189e0696b6075dbf748521a)

source3/include/ntlmssp.h
source3/libsmb/asn1.c
source3/libsmb/cliconnect.c
source3/libsmb/clispnego.c
source3/libsmb/errormap.c
source3/libsmb/ntlmssp.c
source3/libsmb/ntlmssp_parse.c

index 9a79707238d0e4055ea46c7db8cb9399c2318ba7..4fa4259a6a5055cc791453145dd4217f1bf6bd30 100644 (file)
@@ -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;
+
index 333d15790526c1d263442d7502bbaad936b9fab5..09d4fbb6c9abc42aaaec10ec524651064ff42565 100644 (file)
@@ -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 */
index 90a7eca8e71a863709b8dfe98d8cb2469c598879..2b0b9abc9d1d85ac2d4e588bbc606ee6424752ef 100644 (file)
@@ -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));
 }
 
 /****************************************************************************
index 91748c4c7a575ab88dc5d934fa8b2935bb694f4a..e93f1855ddd9100af1528733ed0b3742ca968fd7 100644 (file)
@@ -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;
+}
+
index 09340caccd4d59000a3688b574c180bfa0fa0514..8ee5ee3d31e16d093a47e328abea6190f0924a7c 100644 (file)
@@ -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;
index 92a18d25c03f3f78770ea93704c989d3db2b251b..7992c1e84a569bc16851b8da868060022cdd9bb2 100644 (file)
@@ -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;
+}
index 5f3132694e391f857ceca6245f5d3a14f8a0a0f1..6644a3db713a778338af4ce362d8e194d6177a7d 100644 (file)
@@ -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;