r24755: Use common code for finding the RPC binding in the torture tests.
[gd/samba-autobuild/.git] / source4 / torture / rpc / samlogon.c
index 86bfe48a7585248255fbffeb3e2251d47b9be886..da74067336f989db83740b9becacec438b53fcec 100644 (file)
@@ -9,7 +9,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 #include "librpc/gen_ndr/ndr_netlogon.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
 #include "auth/auth.h"
 #include "lib/crypto/crypto.h"
 #include "lib/cmdline/popt_common.h"
+#include "torture/rpc/rpc.h"
+#include "auth/gensec/schannel_proto.h"
+#include "libcli/auth/libcli_auth.h"
 
 #define TEST_MACHINE_NAME "samlogontest"
 #define TEST_USER_NAME "samlogontestuser"
+#define TEST_USER_NAME_WRONG_WKS "samlogontest2"
+#define TEST_USER_NAME_WRONG_TIME "samlogontest3"
 
 enum ntlm_break {
        BREAK_BOTH,
@@ -42,17 +48,20 @@ enum ntlm_break {
 
 struct samlogon_state {
        TALLOC_CTX *mem_ctx;
+       const char *comment;
        const char *account_name;
        const char *account_domain;
        const char *password;
        struct dcerpc_pipe *p;
        int function_level;
+       uint32_t parameter_control;
        struct netr_LogonSamLogon r;
        struct netr_LogonSamLogonEx r_ex;
        struct netr_LogonSamLogonWithFlags r_flags;
        struct netr_Authenticator auth, auth2;
        struct creds_CredentialState *creds;
-
+       NTSTATUS expected_error;
+       BOOL old_password; /* Allow an old password to be accepted or rejected without error, as well as session key bugs */
        DATA_BLOB chall;
 };
 
@@ -62,6 +71,7 @@ struct samlogon_state {
 */
 static NTSTATUS check_samlogon(struct samlogon_state *samlogon_state, 
                               enum ntlm_break break_which,
+                              uint32_t parameter_control,
                               DATA_BLOB *chall, 
                               DATA_BLOB *lm_response, 
                               DATA_BLOB *nt_response, 
@@ -82,7 +92,7 @@ static NTSTATUS check_samlogon(struct samlogon_state *samlogon_state,
        samlogon_state->r_flags.in.logon.network = &ninfo;
        
        ninfo.identity_info.domain_name.string = samlogon_state->account_domain;
-       ninfo.identity_info.parameter_control = 0;
+       ninfo.identity_info.parameter_control = parameter_control;
        ninfo.identity_info.logon_id_low = 0;
        ninfo.identity_info.logon_id_high = 0;
        ninfo.identity_info.account_name.string = samlogon_state->account_name;
@@ -136,7 +146,7 @@ static NTSTATUS check_samlogon(struct samlogon_state *samlogon_state,
        }
        
        switch (samlogon_state->function_level) {
-       case DCERPC_NETR_LOGONSAMLOGON: 
+       case NDR_NETR_LOGONSAMLOGON: 
                ZERO_STRUCT(samlogon_state->auth2);
                creds_client_authenticator(samlogon_state->creds, &samlogon_state->auth);
 
@@ -144,15 +154,19 @@ static NTSTATUS check_samlogon(struct samlogon_state *samlogon_state,
                status = dcerpc_netr_LogonSamLogon(samlogon_state->p, samlogon_state->mem_ctx, r);
                if (!r->out.return_authenticator || 
                    !creds_client_check(samlogon_state->creds, &r->out.return_authenticator->cred)) {
-                       printf("Credential chaining failed\n");
+                       d_printf("Credential chaining failed\n");
                }
                if (!NT_STATUS_IS_OK(status)) {
                        if (error_string) {
                                *error_string = strdup(nt_errstr(status));
                        }
+                       return status;
                }
 
                validation_level = r->in.validation_level;
+
+               creds_decrypt_samlogon(samlogon_state->creds, validation_level, &r->out.validation);
+
                switch (validation_level) {
                case 2:
                        base = &r->out.validation.sam2->base;
@@ -165,15 +179,19 @@ static NTSTATUS check_samlogon(struct samlogon_state *samlogon_state,
                        break;
                }
                break;
-       case DCERPC_NETR_LOGONSAMLOGONEX: 
+       case NDR_NETR_LOGONSAMLOGONEX: 
                status = dcerpc_netr_LogonSamLogonEx(samlogon_state->p, samlogon_state->mem_ctx, r_ex);
                if (!NT_STATUS_IS_OK(status)) {
                        if (error_string) {
                                *error_string = strdup(nt_errstr(status));
                        }
+                       return status;
                }
 
                validation_level = r_ex->in.validation_level;
+
+               creds_decrypt_samlogon(samlogon_state->creds, validation_level, &r_ex->out.validation);
+
                switch (validation_level) {
                case 2:
                        base = &r_ex->out.validation.sam2->base;
@@ -186,7 +204,7 @@ static NTSTATUS check_samlogon(struct samlogon_state *samlogon_state,
                        break;
                }
                break;
-       case DCERPC_NETR_LOGONSAMLOGONWITHFLAGS: 
+       case NDR_NETR_LOGONSAMLOGONWITHFLAGS: 
                ZERO_STRUCT(samlogon_state->auth2);
                creds_client_authenticator(samlogon_state->creds, &samlogon_state->auth);
 
@@ -194,15 +212,19 @@ static NTSTATUS check_samlogon(struct samlogon_state *samlogon_state,
                status = dcerpc_netr_LogonSamLogonWithFlags(samlogon_state->p, samlogon_state->mem_ctx, r_flags);
                if (!r_flags->out.return_authenticator || 
                    !creds_client_check(samlogon_state->creds, &r_flags->out.return_authenticator->cred)) {
-                       printf("Credential chaining failed\n");
+                       d_printf("Credential chaining failed\n");
                }
                if (!NT_STATUS_IS_OK(status)) {
                        if (error_string) {
                                *error_string = strdup(nt_errstr(status));
                        }
+                       return status;
                }
-
+               
                validation_level = r_flags->in.validation_level;
+
+               creds_decrypt_samlogon(samlogon_state->creds, validation_level, &r_flags->out.validation);
+
                switch (validation_level) {
                case 2:
                        base = &r_flags->out.validation.sam2->base;
@@ -215,70 +237,23 @@ static NTSTATUS check_samlogon(struct samlogon_state *samlogon_state,
                        break;
                }
                break;
+       default:
+               /* can't happen */
+               return NT_STATUS_INVALID_PARAMETER;
        }
                
-
-       if (!NT_STATUS_IS_OK(status)) {
-               /* we cannot check the session key, if the logon failed... */
-               return status;
-       }
-
        if (!base) {
-               printf("No user info returned from 'successful' SamLogon*() call!\n");
+               d_printf("No user info returned from 'successful' SamLogon*() call!\n");
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       /* find and decyrpt the session keys, return in parameters above */
-       if (validation_level == 6) {
-               /* they aren't encrypted! */
-               if (user_session_key) {
-                       memcpy(user_session_key, base->key.key, 16);
-               }
-               if (lm_key) {
-                       memcpy(lm_key, base->LMSessKey.key, 8);
-               }
-       } else if (samlogon_state->creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
-               static const char zeros[16];
-                       
-               if (memcmp(base->key.key, zeros,  
-                          sizeof(base->key.key)) != 0) {
-                       creds_arcfour_crypt(samlogon_state->creds, 
-                                           base->key.key, 
-                                           sizeof(base->key.key));
-               }
-                       
-               if (user_session_key) {
-                       memcpy(user_session_key, base->key.key, 16);
-               }
-                       
-               if (memcmp(base->LMSessKey.key, zeros,  
-                          sizeof(base->LMSessKey.key)) != 0) {
-                       creds_arcfour_crypt(samlogon_state->creds, 
-                                           base->LMSessKey.key, 
-                                           sizeof(base->LMSessKey.key));
-               }
-                       
-               if (lm_key) {
-                       memcpy(lm_key, base->LMSessKey.key, 8);
-               }
-       } else {
-               static const char zeros[16];
-                       
-               if (user_session_key) {
-                       memcpy(user_session_key, base->key.key, 16);
-               }
-
-               if (memcmp(base->LMSessKey.key, zeros,  
-                          sizeof(base->LMSessKey.key)) != 0) {
-                       creds_des_decrypt_LMKey(samlogon_state->creds, 
-                                               &base->LMSessKey);
-               }
-                       
-               if (lm_key) {
-                       memcpy(lm_key, base->LMSessKey.key, 8);
-               }
+       if (user_session_key) {
+               memcpy(user_session_key, base->key.key, 16);
        }
-       
+       if (lm_key) {
+               memcpy(lm_key, base->LMSessKey.key, 8);
+       }
+                       
        return status;
 } 
 
@@ -318,6 +293,7 @@ static BOOL test_lm_ntlm_broken(struct samlogon_state *samlogon_state, enum ntlm
 
        nt_status = check_samlogon(samlogon_state,
                                   break_which,
+                                  samlogon_state->parameter_control,
                                   &samlogon_state->chall,
                                   &lm_response,
                                   &nt_response,
@@ -332,24 +308,34 @@ static BOOL test_lm_ntlm_broken(struct samlogon_state *samlogon_state, enum ntlm
                if (break_which == NO_NT && !lm_good) {
                        return True;
                }
+               /* for 'old' passwords, we allow the server to be OK or wrong password */
+               if (samlogon_state->old_password) {
+                       return True;
+               }
                return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH));
-       }
-
-       if (!NT_STATUS_IS_OK(nt_status)) {
+       } else if (NT_STATUS_EQUAL(NT_STATUS_NOT_FOUND, nt_status) && strchr_m(samlogon_state->account_name, '@')) {
+               return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH) || (break_which == NO_NT));
+       } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
+               SAFE_FREE(*error_string);
+               asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
+               return False;
+       } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
+               return True;
+       } else if (!NT_STATUS_IS_OK(nt_status)) {
                return False;
        }
 
        if (break_which == NO_NT && !lm_good) {
-               printf("LM password is 'long' (> 14 chars and therefore invalid) but login did not fail!");
+               *error_string = strdup("LM password is 'long' (> 14 chars and therefore invalid) but login did not fail!");
                return False;
        }
 
        if (memcmp(lm_hash, lm_key, 
                   sizeof(lm_key)) != 0) {
-               printf("LM Key does not match expectations!\n");
-               printf("lm_key:\n");
+               d_printf("LM Key does not match expectations!\n");
+               d_printf("lm_key:\n");
                dump_data(1, lm_key, 8);
-               printf("expected:\n");
+               d_printf("expected:\n");
                dump_data(1, lm_hash, 8);
                pass = False;
        }
@@ -362,10 +348,10 @@ static BOOL test_lm_ntlm_broken(struct samlogon_state *samlogon_state, enum ntlm
                memset(lm_key_expected+8, '\0', 8);
                if (memcmp(lm_key_expected, user_session_key, 
                           16) != 0) {
-                       printf("NT Session Key does not match expectations (should be first-8 LM hash)!\n");
-                       printf("user_session_key:\n");
+                       *error_string = strdup("NT Session Key does not match expectations (should be first-8 LM hash)!\n");
+                       d_printf("user_session_key:\n");
                        dump_data(1, user_session_key, sizeof(user_session_key));
-                       printf("expected:\n");
+                       d_printf("expected:\n");
                        dump_data(1, lm_key_expected, sizeof(lm_key_expected));
                        pass = False;
                }
@@ -374,10 +360,10 @@ static BOOL test_lm_ntlm_broken(struct samlogon_state *samlogon_state, enum ntlm
        default:
                if (memcmp(session_key.data, user_session_key, 
                           sizeof(user_session_key)) != 0) {
-                       printf("NT Session Key does not match expectations!\n");
-                       printf("user_session_key:\n");
+                       *error_string = strdup("NT Session Key does not match expectations!\n");
+                       d_printf("user_session_key:\n");
                        dump_data(1, user_session_key, 16);
-                       printf("expected:\n");
+                       d_printf("expected:\n");
                        dump_data(1, session_key.data, session_key.length);
                        pass = False;
                }
@@ -410,22 +396,33 @@ static BOOL test_ntlm(struct samlogon_state *samlogon_state, char **error_string
 
 static BOOL test_ntlm_in_lm(struct samlogon_state *samlogon_state, char **error_string) 
 {
+       BOOL lm_good;
        BOOL pass = True;
        NTSTATUS nt_status;
        DATA_BLOB nt_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
+       DATA_BLOB session_key = data_blob_talloc(samlogon_state->mem_ctx, NULL, 16);
 
        uint8_t lm_key[8];
        uint8_t lm_hash[16];
        uint8_t user_session_key[16];
+       uint8_t nt_hash[16];
        
+       ZERO_STRUCT(lm_key);
        ZERO_STRUCT(user_session_key);
 
-       SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data, nt_response.data);
-
-       E_deshash(samlogon_state->password, lm_hash); 
+       SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data, 
+                    nt_response.data);
+       E_md4hash(samlogon_state->password, nt_hash);
+       SMBsesskeygen_ntv1(nt_hash, 
+                          session_key.data);
 
+       lm_good = E_deshash(samlogon_state->password, lm_hash); 
+       if (!lm_good) {
+               ZERO_STRUCT(lm_hash);
+       }
        nt_status = check_samlogon(samlogon_state,
                                   BREAK_NONE,
+                                  samlogon_state->parameter_control,
                                   &samlogon_state->chall,
                                   &nt_response,
                                   NULL,
@@ -433,29 +430,55 @@ static BOOL test_ntlm_in_lm(struct samlogon_state *samlogon_state, char **error_
                                   user_session_key,
                                   error_string);
        
-       if (!NT_STATUS_IS_OK(nt_status)) {
+       if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
+               /* for 'old' passwords, we allow the server to be OK or wrong password */
+               if (samlogon_state->old_password) {
+                       return True;
+               }
+               return False;
+       } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
+               SAFE_FREE(*error_string);
+               asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
+               return False;
+       } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
+               return True;
+       } else if (!NT_STATUS_IS_OK(nt_status)) {
                return False;
        }
 
-       if (memcmp(lm_hash, lm_key, 
-                  sizeof(lm_key)) != 0) {
-               printf("LM Key does not match expectations!\n");
-               printf("lm_key:\n");
-               dump_data(1, lm_key, 8);
-               printf("expected:\n");
-               dump_data(1, lm_hash, 8);
-               pass = False;
+       if (lm_good) {
+               if (memcmp(lm_hash, lm_key, 
+                          sizeof(lm_key)) != 0) {
+                       d_printf("LM Key does not match expectations!\n");
+                       d_printf("lm_key:\n");
+                       dump_data(1, lm_key, 8);
+                       d_printf("expected:\n");
+                       dump_data(1, lm_hash, 8);
+                       pass = False;
+               }
+#if 0
+       } else {
+               if (memcmp(session_key.data, lm_key, 
+                          sizeof(lm_key)) != 0) {
+                       d_printf("LM Key does not match expectations (first 8 session key)!\n");
+                       d_printf("lm_key:\n");
+                       dump_data(1, lm_key, 8);
+                       d_printf("expected:\n");
+                       dump_data(1, session_key.data, 8);
+                       pass = False;
+               }
+#endif
        }
-       if (memcmp(lm_hash, user_session_key, 8) != 0) {
+       if (lm_good && memcmp(lm_hash, user_session_key, 8) != 0) {
                uint8_t lm_key_expected[16];
                memcpy(lm_key_expected, lm_hash, 8);
                memset(lm_key_expected+8, '\0', 8);
                if (memcmp(lm_key_expected, user_session_key, 
                           16) != 0) {
-                       printf("NT Session Key does not match expectations (should be first-8 LM hash)!\n");
-                       printf("user_session_key:\n");
+                       d_printf("NT Session Key does not match expectations (should be first-8 LM hash)!\n");
+                       d_printf("user_session_key:\n");
                        dump_data(1, user_session_key, sizeof(user_session_key));
-                       printf("expected:\n");
+                       d_printf("expected:\n");
                        dump_data(1, lm_key_expected, sizeof(lm_key_expected));
                        pass = False;
                }
@@ -496,6 +519,7 @@ static BOOL test_ntlm_in_both(struct samlogon_state *samlogon_state, char **erro
 
        nt_status = check_samlogon(samlogon_state,
                                   BREAK_NONE,
+                                  samlogon_state->parameter_control,
                                   &samlogon_state->chall,
                                   NULL, 
                                   &nt_response,
@@ -503,25 +527,41 @@ static BOOL test_ntlm_in_both(struct samlogon_state *samlogon_state, char **erro
                                   user_session_key,
                                   error_string);
        
+       if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
+               /* for 'old' passwords, we allow the server to be OK or wrong password */
+               if (samlogon_state->old_password) {
+                       return True;
+               }
+               return False;
+       } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
+               SAFE_FREE(*error_string);
+               asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
+               return False;
+       } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
+               return True;
+       } else if (!NT_STATUS_IS_OK(nt_status)) {
+               return False;
+       }
+
        if (!NT_STATUS_IS_OK(nt_status)) {
                return False;
        }
 
        if (memcmp(lm_hash, lm_key, 
                   sizeof(lm_key)) != 0) {
-               printf("LM Key does not match expectations!\n");
-               printf("lm_key:\n");
+               d_printf("LM Key does not match expectations!\n");
+               d_printf("lm_key:\n");
                dump_data(1, lm_key, 8);
-               printf("expected:\n");
+               d_printf("expected:\n");
                dump_data(1, lm_hash, 8);
                pass = False;
        }
        if (memcmp(session_key.data, user_session_key, 
                   sizeof(user_session_key)) != 0) {
-               printf("NT Session Key does not match expectations!\n");
-               printf("user_session_key:\n");
+               d_printf("NT Session Key does not match expectations!\n");
+               d_printf("user_session_key:\n");
                dump_data(1, user_session_key, 16);
-               printf("expected:\n");
+               d_printf("expected:\n");
                dump_data(1, session_key.data, session_key.length);
                pass = False;
        }
@@ -534,7 +574,15 @@ static BOOL test_ntlm_in_both(struct samlogon_state *samlogon_state, char **erro
  * Test the NTLMv2 and LMv2 responses
  */
 
-static BOOL test_lmv2_ntlmv2_broken(struct samlogon_state *samlogon_state, enum ntlm_break break_which, char **error_string) 
+enum ntlmv2_domain {
+       UPPER_DOMAIN,
+       NO_DOMAIN
+};
+
+static BOOL test_lmv2_ntlmv2_broken(struct samlogon_state *samlogon_state, 
+                                   enum ntlm_break break_which, 
+                                   enum ntlmv2_domain ntlmv2_domain, 
+                                   char **error_string) 
 {
        BOOL pass = True;
        NTSTATUS nt_status;
@@ -542,7 +590,7 @@ static BOOL test_lmv2_ntlmv2_broken(struct samlogon_state *samlogon_state, enum
        DATA_BLOB lmv2_response = data_blob(NULL, 0);
        DATA_BLOB lmv2_session_key = data_blob(NULL, 0);
        DATA_BLOB ntlmv2_session_key = data_blob(NULL, 0);
-       DATA_BLOB names_blob = NTLMv2_generate_names_blob(samlogon_state->mem_ctx, lp_netbios_name(), lp_workgroup());
+       DATA_BLOB names_blob = NTLMv2_generate_names_blob(samlogon_state->mem_ctx, TEST_MACHINE_NAME, lp_workgroup());
 
        uint8_t lm_session_key[8];
        uint8_t user_session_key[16];
@@ -550,19 +598,35 @@ static BOOL test_lmv2_ntlmv2_broken(struct samlogon_state *samlogon_state, enum
        ZERO_STRUCT(lm_session_key);
        ZERO_STRUCT(user_session_key);
        
-       /* TODO - test with various domain cases, and without domain */
-       if (!SMBNTLMv2encrypt(samlogon_state->account_name, samlogon_state->account_domain, 
-                             samlogon_state->password, &samlogon_state->chall,
-                             &names_blob,
-                             &lmv2_response, &ntlmv2_response, 
-                             &lmv2_session_key, &ntlmv2_session_key)) {
-               data_blob_free(&names_blob);
-               return False;
+       switch (ntlmv2_domain) {
+       case UPPER_DOMAIN:
+               if (!SMBNTLMv2encrypt(samlogon_state->mem_ctx, 
+                                     samlogon_state->account_name, samlogon_state->account_domain, 
+                                     samlogon_state->password, &samlogon_state->chall,
+                                     &names_blob,
+                                     &lmv2_response, &ntlmv2_response, 
+                                     &lmv2_session_key, &ntlmv2_session_key)) {
+                       data_blob_free(&names_blob);
+                       return False;
+               }
+               break;
+       case NO_DOMAIN:
+               if (!SMBNTLMv2encrypt(samlogon_state->mem_ctx, 
+                                     samlogon_state->account_name, "",
+                                     samlogon_state->password, &samlogon_state->chall,
+                                     &names_blob,
+                                     &lmv2_response, &ntlmv2_response, 
+                                     &lmv2_session_key, &ntlmv2_session_key)) {
+                       data_blob_free(&names_blob);
+                       return False;
+               }
+               break;
        }
        data_blob_free(&names_blob);
 
        nt_status = check_samlogon(samlogon_state,
                                   break_which,
+                                  samlogon_state->parameter_control,
                                   &samlogon_state->chall,
                                   &lmv2_response,
                                   &ntlmv2_response,
@@ -574,31 +638,42 @@ static BOOL test_lmv2_ntlmv2_broken(struct samlogon_state *samlogon_state, enum
        data_blob_free(&ntlmv2_response);
 
 
-       if (NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
+       if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
+               /* for 'old' passwords, we allow the server to be OK or wrong password */
+               if (samlogon_state->old_password) {
+                       return True;
+               }
                return break_which == BREAK_BOTH;
-       }
-
-       if (!NT_STATUS_IS_OK(nt_status)) {
+       } else if (NT_STATUS_EQUAL(NT_STATUS_NOT_FOUND, nt_status) && strchr_m(samlogon_state->account_name, '@')) {
+               return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH) || (break_which == NO_NT));
+       } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
+               SAFE_FREE(*error_string);
+               asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
+               return False;
+       } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
+               return True;
+       } else if (!NT_STATUS_IS_OK(nt_status)) {
                return False;
        }
 
+
        switch (break_which) {
        case NO_NT:
                if (memcmp(lmv2_session_key.data, user_session_key,
                           sizeof(user_session_key)) != 0) {
-                       printf("USER (LMv2) Session Key does not match expectations!\n");
-                       printf("user_session_key:\n");
+                       d_printf("USER (LMv2) Session Key does not match expectations!\n");
+                       d_printf("user_session_key:\n");
                        dump_data(1, user_session_key, 16);
-                       printf("expected:\n");
+                       d_printf("expected:\n");
                        dump_data(1, lmv2_session_key.data, ntlmv2_session_key.length);
                        pass = False;
                }
                if (memcmp(lmv2_session_key.data, lm_session_key, 
-                          sizeof(lm_session_key)) != 0) {
-                       printf("LM (LMv2) Session Key does not match expectations!\n");
-                       printf("lm_session_key:\n");
+                                  sizeof(lm_session_key)) != 0) {
+                       d_printf("LM (LMv2) Session Key does not match expectations!\n");
+                       d_printf("lm_session_key:\n");
                        dump_data(1, lm_session_key, 8);
-                       printf("expected:\n");
+                       d_printf("expected:\n");
                        dump_data(1, lmv2_session_key.data, 8);
                        pass = False;
                }
@@ -608,18 +683,18 @@ static BOOL test_lmv2_ntlmv2_broken(struct samlogon_state *samlogon_state, enum
                           sizeof(user_session_key)) != 0) {
                        if (memcmp(lmv2_session_key.data, user_session_key,
                                   sizeof(user_session_key)) == 0) {
-                               printf("USER (NTLMv2) Session Key expected, got LMv2 sessesion key instead:\n");
-                               printf("user_session_key:\n");
+                               d_printf("USER (NTLMv2) Session Key expected, got LMv2 sessesion key instead:\n");
+                               d_printf("user_session_key:\n");
                                dump_data(1, user_session_key, 16);
-                               printf("expected:\n");
+                               d_printf("expected:\n");
                                dump_data(1, ntlmv2_session_key.data, ntlmv2_session_key.length);
                                pass = False;
                                
                        } else {
-                               printf("USER (NTLMv2) Session Key does not match expectations!\n");
-                               printf("user_session_key:\n");
+                               d_printf("USER (NTLMv2) Session Key does not match expectations!\n");
+                               d_printf("user_session_key:\n");
                                dump_data(1, user_session_key, 16);
-                               printf("expected:\n");
+                               d_printf("expected:\n");
                                dump_data(1, ntlmv2_session_key.data, ntlmv2_session_key.length);
                                pass = False;
                        }
@@ -628,17 +703,17 @@ static BOOL test_lmv2_ntlmv2_broken(struct samlogon_state *samlogon_state, enum
                           sizeof(lm_session_key)) != 0) {
                        if (memcmp(lmv2_session_key.data, lm_session_key,
                                   sizeof(lm_session_key)) == 0) {
-                               printf("LM (NTLMv2) Session Key expected, got LMv2 sessesion key instead:\n");
-                               printf("user_session_key:\n");
+                               d_printf("LM (NTLMv2) Session Key expected, got LMv2 sessesion key instead:\n");
+                               d_printf("user_session_key:\n");
                                dump_data(1, lm_session_key, 8);
-                               printf("expected:\n");
+                               d_printf("expected:\n");
                                dump_data(1, ntlmv2_session_key.data, 8);
                                pass = False;
                        } else {
-                               printf("LM (NTLMv2) Session Key does not match expectations!\n");
-                               printf("lm_session_key:\n");
+                               d_printf("LM (NTLMv2) Session Key does not match expectations!\n");
+                               d_printf("lm_session_key:\n");
                                dump_data(1, lm_session_key, 8);
-                               printf("expected:\n");
+                               d_printf("expected:\n");
                                dump_data(1, ntlmv2_session_key.data, 8);
                                pass = False;
                        }
@@ -652,7 +727,10 @@ static BOOL test_lmv2_ntlmv2_broken(struct samlogon_state *samlogon_state, enum
  * Test the NTLM and LMv2 responses
  */
 
-static BOOL test_lmv2_ntlm_broken(struct samlogon_state *samlogon_state, enum ntlm_break break_which, char **error_string) 
+static BOOL test_lmv2_ntlm_broken(struct samlogon_state *samlogon_state, 
+                                 enum ntlm_break break_which, 
+                                 enum ntlmv2_domain ntlmv2_domain, 
+                                 char **error_string) 
 {
        BOOL pass = True;
        NTSTATUS nt_status;
@@ -665,6 +743,7 @@ static BOOL test_lmv2_ntlm_broken(struct samlogon_state *samlogon_state, enum nt
        DATA_BLOB ntlm_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
        DATA_BLOB ntlm_session_key = data_blob_talloc(samlogon_state->mem_ctx, NULL, 16);
 
+       BOOL lm_good;
        uint8_t lm_hash[16];
        uint8_t lm_session_key[8];
        uint8_t user_session_key[16];
@@ -675,24 +754,47 @@ static BOOL test_lmv2_ntlm_broken(struct samlogon_state *samlogon_state, enum nt
        E_md4hash(samlogon_state->password, nt_hash);
        SMBsesskeygen_ntv1(nt_hash, 
                           ntlm_session_key.data);
-       E_deshash(samlogon_state->password, lm_hash); 
+
+       lm_good = E_deshash(samlogon_state->password, lm_hash); 
+       if (!lm_good) {
+               ZERO_STRUCT(lm_hash);
+       }
 
        ZERO_STRUCT(lm_session_key);
        ZERO_STRUCT(user_session_key);
-       
-       /* TODO - test with various domain cases, and without domain */
-       if (!SMBNTLMv2encrypt(samlogon_state->account_name, samlogon_state->account_domain, 
-                             samlogon_state->password, &samlogon_state->chall,
-                             &names_blob,
-                             &lmv2_response, &ntlmv2_response, 
-                             &lmv2_session_key, &ntlmv2_session_key)) {
-               data_blob_free(&names_blob);
-               return False;
+
+       switch (ntlmv2_domain) {
+       case UPPER_DOMAIN:
+               /* TODO - test with various domain cases, and without domain */
+               if (!SMBNTLMv2encrypt(samlogon_state->mem_ctx, 
+                                     samlogon_state->account_name, samlogon_state->account_domain, 
+                                     samlogon_state->password, &samlogon_state->chall,
+                                     &names_blob,
+                                     &lmv2_response, &ntlmv2_response, 
+                                     &lmv2_session_key, &ntlmv2_session_key)) {
+                       data_blob_free(&names_blob);
+                       return False;
+               }
+               break;
+       case NO_DOMAIN:
+               /* TODO - test with various domain cases, and without domain */
+               if (!SMBNTLMv2encrypt(samlogon_state->mem_ctx, 
+                                     samlogon_state->account_name, "",
+                                     samlogon_state->password, &samlogon_state->chall,
+                                     &names_blob,
+                                     &lmv2_response, &ntlmv2_response, 
+                                     &lmv2_session_key, &ntlmv2_session_key)) {
+                       data_blob_free(&names_blob);
+                       return False;
+               }
+               break;
        }
+
        data_blob_free(&names_blob);
 
        nt_status = check_samlogon(samlogon_state,
                                   break_which,
+                                  samlogon_state->parameter_control,
                                   &samlogon_state->chall,
                                   &lmv2_response,
                                   &ntlm_response,
@@ -705,10 +807,20 @@ static BOOL test_lmv2_ntlm_broken(struct samlogon_state *samlogon_state, enum nt
 
 
        if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
+               /* for 'old' passwords, we allow the server to be OK or wrong password */
+               if (samlogon_state->old_password) {
+                       return True;
+               }
                return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH));
-       }
-
-       if (!NT_STATUS_IS_OK(nt_status)) {
+       } else if (NT_STATUS_EQUAL(NT_STATUS_NOT_FOUND, nt_status) && strchr_m(samlogon_state->account_name, '@')) {
+               return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH));
+       } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
+               SAFE_FREE(*error_string);
+               asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
+               return False;
+       } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
+               return True;
+       } else if (!NT_STATUS_IS_OK(nt_status)) {
                return False;
        }
 
@@ -716,19 +828,19 @@ static BOOL test_lmv2_ntlm_broken(struct samlogon_state *samlogon_state, enum nt
        case NO_NT:
                if (memcmp(lmv2_session_key.data, user_session_key, 
                           sizeof(user_session_key)) != 0) {
-                       printf("USER (LMv2) Session Key does not match expectations!\n");
-                       printf("user_session_key:\n");
+                       d_printf("USER (LMv2) Session Key does not match expectations!\n");
+                       d_printf("user_session_key:\n");
                        dump_data(1, user_session_key, 16);
-                       printf("expected:\n");
+                       d_printf("expected:\n");
                        dump_data(1, lmv2_session_key.data, ntlmv2_session_key.length);
                        pass = False;
                }
                if (memcmp(lmv2_session_key.data, lm_session_key, 
                           sizeof(lm_session_key)) != 0) {
-                       printf("LM (LMv2) Session Key does not match expectations!\n");
-                       printf("lm_session_key:\n");
+                       d_printf("LM (LMv2) Session Key does not match expectations!\n");
+                       d_printf("lm_session_key:\n");
                        dump_data(1, lm_session_key, 8);
-                       printf("expected:\n");
+                       d_printf("expected:\n");
                        dump_data(1, lmv2_session_key.data, 8);
                        pass = False;
                }
@@ -736,39 +848,52 @@ static BOOL test_lmv2_ntlm_broken(struct samlogon_state *samlogon_state, enum nt
        case BREAK_LM:
                if (memcmp(ntlm_session_key.data, user_session_key, 
                           sizeof(user_session_key)) != 0) {
-                       printf("USER (NTLMv2) Session Key does not match expectations!\n");
-                       printf("user_session_key:\n");
+                       d_printf("USER (NTLMv2) Session Key does not match expectations!\n");
+                       d_printf("user_session_key:\n");
                        dump_data(1, user_session_key, 16);
-                       printf("expected:\n");
+                       d_printf("expected:\n");
                        dump_data(1, ntlm_session_key.data, ntlm_session_key.length);
                        pass = False;
                }
-               if (memcmp(lm_hash, lm_session_key, 
-                          sizeof(lm_session_key)) != 0) {
-                       printf("LM Session Key does not match expectations!\n");
-                       printf("lm_session_key:\n");
-                       dump_data(1, lm_session_key, 8);
-                       printf("expected:\n");
-                       dump_data(1, lm_hash, 8);
-                       pass = False;
+               if (lm_good) {
+                       if (memcmp(lm_hash, lm_session_key, 
+                                  sizeof(lm_session_key)) != 0) {
+                               d_printf("LM Session Key does not match expectations!\n");
+                               d_printf("lm_session_key:\n");
+                               dump_data(1, lm_session_key, 8);
+                               d_printf("expected:\n");
+                               dump_data(1, lm_hash, 8);
+                               pass = False;
+                       }
+               } else {
+                       static const uint8_t zeros[8];
+                       if (memcmp(zeros, lm_session_key, 
+                                  sizeof(lm_session_key)) != 0) {
+                               d_printf("LM Session Key does not match expectations (zeros)!\n");
+                               d_printf("lm_session_key:\n");
+                               dump_data(1, lm_session_key, 8);
+                               d_printf("expected:\n");
+                               dump_data(1, zeros, 8);
+                               pass = False;
+                       }
                }
                break;
        default:
                if (memcmp(ntlm_session_key.data, user_session_key, 
                           sizeof(user_session_key)) != 0) {
-                       printf("USER (NTLMv2) Session Key does not match expectations!\n");
-                       printf("user_session_key:\n");
+                       d_printf("USER (NTLMv2) Session Key does not match expectations!\n");
+                       d_printf("user_session_key:\n");
                        dump_data(1, user_session_key, 16);
-                       printf("expected:\n");
+                       d_printf("expected:\n");
                        dump_data(1, ntlm_session_key.data, ntlm_session_key.length);
                        pass = False;
                }
                if (memcmp(ntlm_session_key.data, lm_session_key, 
                           sizeof(lm_session_key)) != 0) {
-                       printf("LM (NTLMv2) Session Key does not match expectations!\n");
-                       printf("lm_session_key:\n");
+                       d_printf("LM (NTLMv2) Session Key does not match expectations!\n");
+                       d_printf("lm_session_key:\n");
                        dump_data(1, lm_session_key, 8);
-                       printf("expected:\n");
+                       d_printf("expected:\n");
                        dump_data(1, ntlm_session_key.data, 8);
                        pass = False;
                }
@@ -783,16 +908,28 @@ static BOOL test_lmv2_ntlm_broken(struct samlogon_state *samlogon_state, enum nt
 
 static BOOL test_lmv2_ntlmv2(struct samlogon_state *samlogon_state, char **error_string) 
 {
-       return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_NONE, error_string);
+       return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_NONE, UPPER_DOMAIN, error_string);
 }
 
+#if 0
+static BOOL test_lmv2_ntlmv2_no_dom(struct samlogon_state *samlogon_state, char **error_string) 
+{
+       return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_NONE, NO_DOMAIN, error_string);
+}
+#endif
+
 /* 
  * Test the LMv2 response only
  */
 
 static BOOL test_lmv2(struct samlogon_state *samlogon_state, char **error_string) 
 {
-       return test_lmv2_ntlmv2_broken(samlogon_state, NO_NT, error_string);
+       return test_lmv2_ntlmv2_broken(samlogon_state, NO_NT, UPPER_DOMAIN, error_string);
+}
+
+static BOOL test_lmv2_no_dom(struct samlogon_state *samlogon_state, char **error_string) 
+{
+       return test_lmv2_ntlmv2_broken(samlogon_state, NO_NT, NO_DOMAIN, error_string);
 }
 
 /* 
@@ -801,7 +938,12 @@ static BOOL test_lmv2(struct samlogon_state *samlogon_state, char **error_string
 
 static BOOL test_ntlmv2(struct samlogon_state *samlogon_state, char **error_string) 
 {
-       return test_lmv2_ntlmv2_broken(samlogon_state, NO_LM, error_string);
+       return test_lmv2_ntlmv2_broken(samlogon_state, NO_LM, UPPER_DOMAIN, error_string);
+}
+
+static BOOL test_ntlmv2_no_dom(struct samlogon_state *samlogon_state, char **error_string) 
+{
+       return test_lmv2_ntlmv2_broken(samlogon_state, NO_LM, NO_DOMAIN, error_string);
 }
 
 static BOOL test_lm_ntlm(struct samlogon_state *samlogon_state, char **error_string) 
@@ -825,32 +967,64 @@ static BOOL test_lm_ntlm_both_broken(struct samlogon_state *samlogon_state, char
 }
 static BOOL test_ntlmv2_lmv2_broken(struct samlogon_state *samlogon_state, char **error_string) 
 {
-       return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_LM, error_string);
+       return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_LM, UPPER_DOMAIN, error_string);
+}
+
+static BOOL test_ntlmv2_lmv2_broken_no_dom(struct samlogon_state *samlogon_state, char **error_string) 
+{
+       return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_LM, NO_DOMAIN, error_string);
 }
 
 static BOOL test_ntlmv2_ntlmv2_broken(struct samlogon_state *samlogon_state, char **error_string) 
 {
-       return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_NT, error_string);
+       return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_NT, UPPER_DOMAIN, error_string);
+}
+
+#if 0
+static BOOL test_ntlmv2_ntlmv2_broken_no_dom(struct samlogon_state *samlogon_state, char **error_string) 
+{
+       return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_NT, NO_DOMAIN, error_string);
 }
+#endif
 
 static BOOL test_ntlmv2_both_broken(struct samlogon_state *samlogon_state, char **error_string) 
 {
-       return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_BOTH, error_string);
+       return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_BOTH, UPPER_DOMAIN, error_string);
+}
+
+static BOOL test_ntlmv2_both_broken_no_dom(struct samlogon_state *samlogon_state, char **error_string) 
+{
+       return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_BOTH, NO_DOMAIN, error_string);
 }
 
 static BOOL test_lmv2_ntlm_both_broken(struct samlogon_state *samlogon_state, char **error_string) 
 {
-       return test_lmv2_ntlm_broken(samlogon_state, BREAK_BOTH, error_string);
+       return test_lmv2_ntlm_broken(samlogon_state, BREAK_BOTH, UPPER_DOMAIN, error_string);
+}
+
+static BOOL test_lmv2_ntlm_both_broken_no_dom(struct samlogon_state *samlogon_state, char **error_string) 
+{
+       return test_lmv2_ntlm_broken(samlogon_state, BREAK_BOTH, NO_DOMAIN, error_string);
 }
 
 static BOOL test_lmv2_ntlm_break_ntlm(struct samlogon_state *samlogon_state, char **error_string) 
 {
-       return test_lmv2_ntlm_broken(samlogon_state, BREAK_NT, error_string);
+       return test_lmv2_ntlm_broken(samlogon_state, BREAK_NT, UPPER_DOMAIN, error_string);
+}
+
+static BOOL test_lmv2_ntlm_break_ntlm_no_dom(struct samlogon_state *samlogon_state, char **error_string) 
+{
+       return test_lmv2_ntlm_broken(samlogon_state, BREAK_NT, NO_DOMAIN, error_string);
 }
 
 static BOOL test_lmv2_ntlm_break_lm(struct samlogon_state *samlogon_state, char **error_string) 
 {
-       return test_lmv2_ntlm_broken(samlogon_state, BREAK_LM, error_string);
+       return test_lmv2_ntlm_broken(samlogon_state, BREAK_LM, UPPER_DOMAIN, error_string);
+}
+
+static BOOL test_lmv2_ntlm_break_lm_no_dom(struct samlogon_state *samlogon_state, char **error_string) 
+{
+       return test_lmv2_ntlm_broken(samlogon_state, BREAK_LM, NO_DOMAIN, error_string);
 }
 
 /* 
@@ -868,6 +1042,7 @@ static BOOL test_ntlm2(struct samlogon_state *samlogon_state, char **error_strin
        DATA_BLOB lm_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
        DATA_BLOB nt_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
 
+       BOOL lm_good;
        uint8_t lm_key[8];
        uint8_t nt_hash[16];
        uint8_t lm_hash[16];
@@ -890,7 +1065,7 @@ static BOOL test_ntlm2(struct samlogon_state *samlogon_state, char **error_strin
        MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
        
        E_md4hash(samlogon_state->password, (uint8_t *)nt_hash);
-       E_deshash(samlogon_state->password, (uint8_t *)lm_hash);
+       lm_good = E_deshash(samlogon_state->password, (uint8_t *)lm_hash);
        SMBsesskeygen_ntv1((const uint8_t *)nt_hash, 
                           nt_key);
 
@@ -906,6 +1081,7 @@ static BOOL test_ntlm2(struct samlogon_state *samlogon_state, char **error_strin
 
        nt_status = check_samlogon(samlogon_state,
                                   BREAK_NONE,
+                                  samlogon_state->parameter_control,
                                   &samlogon_state->chall,
                                   &lm_response,
                                   &nt_response,
@@ -913,24 +1089,49 @@ static BOOL test_ntlm2(struct samlogon_state *samlogon_state, char **error_strin
                                   user_session_key,
                                   error_string);
        
-       if (!NT_STATUS_IS_OK(nt_status)) {
+       if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
+               /* for 'old' passwords, we allow the server to be OK or wrong password */
+               if (samlogon_state->old_password) {
+                       return True;
+               }
+               return False;
+       } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
+               SAFE_FREE(*error_string);
+               asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
+               return False;
+       } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
+               return True;
+       } else if (!NT_STATUS_IS_OK(nt_status)) {
                return False;
        }
 
-       if (memcmp(lm_hash, lm_key, 
-                  sizeof(lm_key)) != 0) {
-               printf("LM Key does not match expectations!\n");
-               printf("lm_key:\n");
-               dump_data(1, lm_key, 8);
-               printf("expected:\n");
-               dump_data(1, lm_hash, 8);
-               pass = False;
+       if (lm_good) {
+               if (memcmp(lm_hash, lm_key, 
+                          sizeof(lm_key)) != 0) {
+                       d_printf("LM Key does not match expectations!\n");
+                       d_printf("lm_key:\n");
+                       dump_data(1, lm_key, 8);
+                       d_printf("expected:\n");
+                       dump_data(1, lm_hash, 8);
+                       pass = False;
+               }
+       } else {
+               static const uint8_t zeros[8];
+               if (memcmp(zeros, lm_key, 
+                          sizeof(lm_key)) != 0) {
+                       d_printf("LM Session Key does not match expectations (zeros)!\n");
+                       d_printf("lm_key:\n");
+                       dump_data(1, lm_key, 8);
+                       d_printf("expected:\n");
+                       dump_data(1, zeros, 8);
+                       pass = False;
+               }
        }
        if (memcmp(nt_key, user_session_key, 16) != 0) {
-               printf("NT Session Key does not match expectations (should be first-8 LM hash)!\n");
-               printf("user_session_key:\n");
+               d_printf("NT Session Key does not match expectations (should be NT Key)!\n");
+               d_printf("user_session_key:\n");
                dump_data(1, user_session_key, sizeof(user_session_key));
-               printf("expected:\n");
+               d_printf("expected:\n");
                dump_data(1, nt_key, sizeof(nt_key));
                pass = False;
        }
@@ -948,8 +1149,10 @@ static BOOL test_plaintext(struct samlogon_state *samlogon_state, enum ntlm_brea
 
        uint8_t user_session_key[16];
        uint8_t lm_key[16];
+       uint8_t lm_hash[16];
        static const uint8_t zeros[8];
        DATA_BLOB chall = data_blob_talloc(samlogon_state->mem_ctx, zeros, sizeof(zeros));
+       BOOL lm_good = E_deshash(samlogon_state->password, lm_hash); 
 
        ZERO_STRUCT(user_session_key);
        
@@ -975,6 +1178,7 @@ static BOOL test_plaintext(struct samlogon_state *samlogon_state, enum ntlm_brea
 
        nt_status = check_samlogon(samlogon_state,
                                   break_which,
+                                  samlogon_state->parameter_control | MSV1_0_CLEARTEXT_PASSWORD_ALLOWED,
                                   &chall,
                                   &lm_response,
                                   &nt_response,
@@ -982,8 +1186,31 @@ static BOOL test_plaintext(struct samlogon_state *samlogon_state, enum ntlm_brea
                                   user_session_key,
                                   error_string);
        
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               return break_which == BREAK_NT;
+       if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
+               /* for 'old' passwords, we allow the server to be OK or wrong password */
+               if (samlogon_state->old_password) {
+                       return True;
+               }
+               /* for 'long' passwords, the LM password is invalid */
+               if (break_which == NO_NT && !lm_good) {
+                       return True;
+               }
+               return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH));
+       } else if (NT_STATUS_EQUAL(NT_STATUS_NOT_FOUND, nt_status) && strchr_m(samlogon_state->account_name, '@')) {
+               return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH) || (break_which == NO_NT));
+       } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
+               SAFE_FREE(*error_string);
+               asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
+               return False;
+       } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
+               return True;
+       } else if (!NT_STATUS_IS_OK(nt_status)) {
+               return False;
+       }
+
+       if (break_which == NO_NT && !lm_good) {
+               *error_string = strdup("LM password is 'long' (> 14 chars and therefore invalid) but login did not fail!");
+               return False;
        }
 
        return True;
@@ -1038,6 +1265,9 @@ static const struct ntlm_tests {
        BOOL expect_fail;
 } test_table[] = {
        {test_lmv2_ntlmv2, "NTLMv2 and LMv2", False},
+#if 0
+       {test_lmv2_ntlmv2_no_dom, "NTLMv2 and LMv2 (no domain)", False},
+#endif
        {test_lm, "LM", False},
        {test_lm_ntlm, "LM and NTLM", False},
        {test_lm_ntlm_both_broken, "LM and NTLM, both broken", False},
@@ -1045,21 +1275,31 @@ static const struct ntlm_tests {
        {test_ntlm_in_lm, "NTLM in LM", False},
        {test_ntlm_in_both, "NTLM in both", False},
        {test_ntlmv2, "NTLMv2", False},
+       {test_ntlmv2_no_dom, "NTLMv2 (no domain)", False},
        {test_lmv2, "LMv2", False},
+       {test_lmv2_no_dom, "LMv2 (no domain)", False},
        {test_ntlmv2_lmv2_broken, "NTLMv2 and LMv2, LMv2 broken", False},
+       {test_ntlmv2_lmv2_broken_no_dom, "NTLMv2 and LMv2, LMv2 broken (no domain)", False},
        {test_ntlmv2_ntlmv2_broken, "NTLMv2 and LMv2, NTLMv2 broken", False},
+#if 0
+       {test_ntlmv2_ntlmv2_broken_no_dom, "NTLMv2 and LMv2, NTLMv2 broken (no domain)", False},
+#endif
        {test_ntlmv2_both_broken, "NTLMv2 and LMv2, both broken", False},
+       {test_ntlmv2_both_broken_no_dom, "NTLMv2 and LMv2, both broken (no domain)", False},
        {test_ntlm_lm_broken, "NTLM and LM, LM broken", False},
        {test_ntlm_ntlm_broken, "NTLM and LM, NTLM broken", False},
        {test_ntlm2, "NTLM2 (NTLMv2 session security)", False},
        {test_lmv2_ntlm_both_broken, "LMv2 and NTLM, both broken", False},
+       {test_lmv2_ntlm_both_broken_no_dom, "LMv2 and NTLM, both broken (no domain)", False},
        {test_lmv2_ntlm_break_ntlm, "LMv2 and NTLM, NTLM broken", False},
+       {test_lmv2_ntlm_break_ntlm_no_dom, "LMv2 and NTLM, NTLM broken (no domain)", False},
        {test_lmv2_ntlm_break_lm, "LMv2 and NTLM, LMv2 broken", False},
-       {test_plaintext_none_broken, "Plaintext", True},
-       {test_plaintext_lm_broken, "Plaintext LM broken", True},
-       {test_plaintext_nt_broken, "Plaintext NT broken", True},
-       {test_plaintext_nt_only, "Plaintext NT only", True},
-       {test_plaintext_lm_only, "Plaintext LM only", True},
+       {test_lmv2_ntlm_break_lm_no_dom, "LMv2 and NTLM, LMv2 broken (no domain)", False},
+       {test_plaintext_none_broken, "Plaintext", False},
+       {test_plaintext_lm_broken, "Plaintext LM broken", False},
+       {test_plaintext_nt_broken, "Plaintext NT broken", False},
+       {test_plaintext_nt_only, "Plaintext NT only", False},
+       {test_plaintext_lm_only, "Plaintext LM only", False},
        {NULL, NULL}
 };
 
@@ -1068,8 +1308,10 @@ static const struct ntlm_tests {
 */
 static BOOL test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
                          struct creds_CredentialState *creds, 
+                         const char *comment,
                          const char *account_domain, const char *account_name, 
-                         const char *plain_pass,
+                         const char *plain_pass, uint32_t parameter_control,
+                         NTSTATUS expected_error, BOOL old_password,
                          int n_subtests)
 {
        TALLOC_CTX *fn_ctx = talloc_named(mem_ctx, 0, "test_SamLogon function-level context");
@@ -1078,34 +1320,37 @@ static BOOL test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        int validation_levels[] = {2,3,6};
        int logon_levels[] = { 2, 6 };
        int function_levels[] = { 
-               DCERPC_NETR_LOGONSAMLOGON,
-               DCERPC_NETR_LOGONSAMLOGONEX,
-               DCERPC_NETR_LOGONSAMLOGONWITHFLAGS };
+               NDR_NETR_LOGONSAMLOGON,
+               NDR_NETR_LOGONSAMLOGONEX,
+               NDR_NETR_LOGONSAMLOGONWITHFLAGS };
        struct samlogon_state samlogon_state;
        
-       printf("testing netr_LogonSamLogon and netr_LogonSamLogonWithFlags\n");
+       d_printf("testing netr_LogonSamLogon and netr_LogonSamLogonWithFlags\n");
        
+       samlogon_state.comment = comment;
        samlogon_state.account_name = account_name;
        samlogon_state.account_domain = account_domain;
        samlogon_state.password = plain_pass;
        samlogon_state.p = p;
        samlogon_state.creds = creds;
-
+       samlogon_state.expected_error = expected_error;
        samlogon_state.chall = data_blob_talloc(fn_ctx, NULL, 8);
+       samlogon_state.parameter_control = parameter_control;
+       samlogon_state.old_password = old_password;
 
        generate_random_buffer(samlogon_state.chall.data, 8);
        samlogon_state.r_flags.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p));
-       samlogon_state.r_flags.in.workstation = TEST_MACHINE_NAME;
+       samlogon_state.r_flags.in.computer_name = TEST_MACHINE_NAME;
        samlogon_state.r_flags.in.credential = &samlogon_state.auth;
        samlogon_state.r_flags.in.return_authenticator = &samlogon_state.auth2;
        samlogon_state.r_flags.in.flags = 0;
 
        samlogon_state.r_ex.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p));
-       samlogon_state.r_ex.in.workstation = TEST_MACHINE_NAME;
+       samlogon_state.r_ex.in.computer_name = TEST_MACHINE_NAME;
        samlogon_state.r_ex.in.flags = 0;
 
        samlogon_state.r.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p));
-       samlogon_state.r.in.workstation = TEST_MACHINE_NAME;
+       samlogon_state.r.in.computer_name = TEST_MACHINE_NAME;
        samlogon_state.r.in.credential = &samlogon_state.auth;
        samlogon_state.r.in.return_authenticator = &samlogon_state.auth2;
 
@@ -1127,16 +1372,17 @@ static BOOL test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
                                        samlogon_state.r_flags.in.validation_level = validation_levels[v];
                                        samlogon_state.r_flags.in.logon_level = logon_levels[l];
                                        if (!test_table[i].fn(&samlogon_state, &error_string)) {
-                                               printf("Testing [%s]\\[%s] '%s' at validation level %d, logon level %d, function %d: \n", 
+                                               d_printf("Testing '%s' [%s]\\[%s] '%s' at validation level %d, logon level %d, function %d: \n",
+                                                      samlogon_state.comment,
                                                       samlogon_state.account_domain,
                                                       samlogon_state.account_name,
                                                       test_table[i].name, validation_levels[v], 
                                                       logon_levels[l], function_levels[f]);
                                                
                                                if (test_table[i].expect_fail) {
-                                                       printf(" failed (expected, test incomplete): %s\n", error_string);
+                                                       d_printf(" failed (expected, test incomplete): %s\n", error_string);
                                                } else {
-                                                       printf(" failed: %s\n", error_string);
+                                                       d_printf(" failed: %s\n", error_string);
                                                        ret = False;
                                                }
                                                SAFE_FREE(error_string);
@@ -1153,10 +1399,13 @@ static BOOL test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
 /*
   test an ADS style interactive domain logon
 */
-static BOOL test_InteractiveLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
-                                 struct creds_CredentialState *creds, 
-                                 const char *account_domain, const char *account_name,
-                                 const char *plain_pass)
+BOOL test_InteractiveLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+                          struct creds_CredentialState *creds, 
+                          const char *comment,
+                          const char *workstation_name,
+                          const char *account_domain, const char *account_name,
+                          const char *plain_pass, uint32_t parameter_control, 
+                          NTSTATUS expected_error)
 {
        NTSTATUS status;
        TALLOC_CTX *fn_ctx = talloc_named(mem_ctx, 0, "test_InteractiveLogon function-level context");
@@ -1171,7 +1420,7 @@ static BOOL test_InteractiveLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        creds_client_authenticator(creds, &a);
 
        r.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p));
-       r.in.workstation = TEST_MACHINE_NAME;
+       r.in.computer_name = TEST_MACHINE_NAME;
        r.in.credential = &a;
        r.in.return_authenticator = &ra;
        r.in.logon_level = 5;
@@ -1180,13 +1429,15 @@ static BOOL test_InteractiveLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        r.in.flags = 0;
 
        pinfo.identity_info.domain_name.string = account_domain;
-       pinfo.identity_info.parameter_control = 0;
+       pinfo.identity_info.parameter_control = parameter_control;
        pinfo.identity_info.logon_id_low = 0;
        pinfo.identity_info.logon_id_high = 0;
        pinfo.identity_info.account_name.string = account_name;
-       pinfo.identity_info.workstation.string = TEST_MACHINE_NAME;
+       pinfo.identity_info.workstation.string = workstation_name;
 
-       E_deshash(plain_pass, pinfo.lmpassword.hash);
+       if (!E_deshash(plain_pass, pinfo.lmpassword.hash)) {
+               ZERO_STRUCT(pinfo.lmpassword.hash);
+       }
        E_md4hash(plain_pass, pinfo.ntpassword.hash);
 
        if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
@@ -1197,19 +1448,21 @@ static BOOL test_InteractiveLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
                creds_des_encrypt(creds, &pinfo.ntpassword);
        }
 
-       printf("Testing netr_LogonSamLogonWithFlags (Interactive Logon)\n");
+       d_printf("Testing netr_LogonSamLogonWithFlags '%s' (Interactive Logon)\n", comment);
 
        status = dcerpc_netr_LogonSamLogonWithFlags(p, fn_ctx, &r);
-       if (!r.out.return_authenticator || !creds_client_check(creds, &r.out.return_authenticator->cred)) {
-               printf("Credential chaining failed\n");
+       if (!r.out.return_authenticator 
+           || !creds_client_check(creds, &r.out.return_authenticator->cred)) {
+               d_printf("Credential chaining failed\n");
                talloc_free(fn_ctx);
                return False;
        }
 
        talloc_free(fn_ctx);
 
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("[%s]\\[%s] netr_LogonSamLogonWithFlags - %s\n", account_name, account_domain, nt_errstr(status));
+       if (!NT_STATUS_EQUAL(expected_error, status)) {
+               d_printf("[%s]\\[%s] netr_LogonSamLogonWithFlags - expected %s got %s\n", 
+                      account_domain, account_name, nt_errstr(expected_error), nt_errstr(status));
                return False;
        }
 
@@ -1218,22 +1471,22 @@ static BOOL test_InteractiveLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
 
 
 
-BOOL torture_rpc_samlogon(void)
+BOOL torture_rpc_samlogon(struct torture_context *torture)
 {
         NTSTATUS status;
         struct dcerpc_pipe *p;
        struct dcerpc_binding *b;
-       struct cli_credentials *credentials;
+       struct cli_credentials *machine_credentials;
        TALLOC_CTX *mem_ctx = talloc_init("torture_rpc_netlogon");
        BOOL ret = True;
-       struct test_join *join_ctx;
-#if 0
-       struct test_join *user_ctx;
-       const char *user_password;
-#endif
+       struct test_join *join_ctx = NULL;
+       struct test_join *user_ctx = NULL, *user_ctx_wrong_wks = NULL, *user_ctx_wrong_time = NULL;
+       char *user_password, *user_password_wrong_wks, *user_password_wrong_time;
+       const char *old_user_password;
        char *test_machine_account;
-       const char *machine_password;
-       const char *binding = lp_parm_string(-1, "torture", "binding");
+       const char *userdomain;
+       struct samr_SetUserInfo s;
+       union samr_UserInfo u;
        int i;
        int ci;
 
@@ -1247,96 +1500,89 @@ BOOL torture_rpc_samlogon(void)
 
        struct creds_CredentialState *creds;
 
-       struct {
-               const char *domain;
-               const char *username;
-               const char *password;
-               BOOL network_login;
-       } usercreds[] = {
-               {
-                       cli_credentials_get_domain(cmdline_credentials),
-                       cli_credentials_get_username(cmdline_credentials),
-                       cli_credentials_get_password(cmdline_credentials),
-                       True
-               },
-               {
-                       NULL,
-                       talloc_asprintf(mem_ctx, 
-                                       "%s@%s", 
-                                       cli_credentials_get_username(cmdline_credentials),
-                                       cli_credentials_get_domain(cmdline_credentials)
-                               ),
-                       cli_credentials_get_password(cmdline_credentials),
-                       False
-               },
-               {
-                       NULL,
-                       talloc_asprintf(mem_ctx, 
-                                       "%s@%s", 
-                                       cli_credentials_get_username(cmdline_credentials),
-                                       cli_credentials_get_realm(cmdline_credentials)
-                               ),
-                       cli_credentials_get_password(cmdline_credentials),
-                       True
-               },
-#if 0
-               {       
-                       lp_parm_string(-1, "torture", "userdomain"),
-                       TEST_USER_NAME,
-                       NULL,
-                       True
-               },
-               {
-                       NULL,
-                       talloc_asprintf(mem_ctx, 
-                                       "%s@%s", 
-                                       TEST_USER_NAME,
-                                       lp_realm()),
-                       NULL,
-                       True
-               },
-               {
-                       NULL,
-                       talloc_asprintf(mem_ctx, 
-                                       "%s@%s", 
-                                       TEST_USER_NAME,
-                                       lp_parm_string(-1, "torture", "userdomain")),
-                       NULL,
-                       False
-               }
-#endif
-       };
-               
-       credentials = cli_credentials_init(mem_ctx);
-
        test_machine_account = talloc_asprintf(mem_ctx, "%s$", TEST_MACHINE_NAME);
        /* We only need to join as a workstation here, and in future,
         * if we wish to test against trusted domains, we must be a
         * workstation here */
-       join_ctx = torture_create_testuser(test_machine_account, lp_workgroup(), ACB_WSTRUST, 
-                                          &machine_password);
+       join_ctx = torture_join_domain(TEST_MACHINE_NAME, ACB_WSTRUST, 
+                                      &machine_credentials);
        if (!join_ctx) {
-               printf("Failed to join as Workstation\n");
+               d_printf("Failed to join as Workstation\n");
                return False;
        }
-#if 0
-       user_ctx = torture_create_testuser(TEST_USER_NAME,
-                                          lp_parm_string(-1, "torture", "userdomain"),
+
+       userdomain = torture_setting_string(torture, "userdomain", lp_workgroup());
+
+       user_ctx = torture_create_testuser(torture,
+                                          TEST_USER_NAME,
+                                          userdomain,
                                           ACB_NORMAL, 
-                                          &user_password);
+                                          (const char **)&user_password);
        if (!user_ctx) {
-               printf("Failed to join as Workstation\n");
+               d_printf("Failed to create a test user\n");
                return False;
        }
 
-       usercreds[3].password = user_password;
-       usercreds[4].password = user_password;
-       usercreds[5].password = user_password;
-#endif
+       old_user_password = user_password;
+
+       test_ChangePasswordUser3(torture_join_samr_pipe(user_ctx), mem_ctx,
+                                TEST_USER_NAME, 16 /* > 14 */, &user_password, 
+                                NULL, 0, False);
+
+       user_ctx_wrong_wks = torture_create_testuser(torture,
+                                                    TEST_USER_NAME_WRONG_WKS,
+                                          userdomain,
+                                          ACB_NORMAL, 
+                                          (const char **)&user_password_wrong_wks);
+       if (!user_ctx_wrong_wks) {
+               d_printf("Failed to create a test user (wrong workstation test)\n");
+               return False;
+       }
+
+       ZERO_STRUCT(u);
+       s.in.user_handle = torture_join_samr_user_policy(user_ctx_wrong_wks);
+       s.in.info = &u;
+       s.in.level = 21;
+
+       u.info21.fields_present = SAMR_FIELD_WORKSTATIONS;
+       u.info21.workstations.string = "not" TEST_MACHINE_NAME;
+
+       status = dcerpc_samr_SetUserInfo(torture_join_samr_pipe(user_ctx_wrong_wks), mem_ctx, &s);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("SetUserInfo (list of workstations) failed - %s\n", nt_errstr(status));
+               ret = False;
+               goto failed;
+       }
+
+       user_ctx_wrong_time
+               = torture_create_testuser(torture, TEST_USER_NAME_WRONG_TIME,
+                                          userdomain,
+                                          ACB_NORMAL, 
+                                          (const char **)&user_password_wrong_time);
+       if (!user_ctx_wrong_time) {
+               d_printf("Failed to create a test user (wrong workstation test)\n");
+               return False;
+       }
+
+       ZERO_STRUCT(u);
+       s.in.user_handle = torture_join_samr_user_policy(user_ctx_wrong_time);
+       s.in.info = &u;
+       s.in.level = 21;
+
+       u.info21.fields_present = SAMR_FIELD_WORKSTATIONS | SAMR_FIELD_LOGON_HOURS;
+       u.info21.workstations.string = TEST_MACHINE_NAME;
+       u.info21.logon_hours.units_per_week = 168;
+       u.info21.logon_hours.bits = talloc_zero_size(mem_ctx, 168);
 
-       status = dcerpc_parse_binding(mem_ctx, binding, &b);
+       status = dcerpc_samr_SetUserInfo(torture_join_samr_pipe(user_ctx_wrong_time), mem_ctx, &s);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("SetUserInfo (logon times and list of workstations) failed - %s\n", nt_errstr(status));
+               ret = False;
+               goto failed;
+       }
+
+       status = torture_rpc_binding(torture, &b);
        if (!NT_STATUS_IS_OK(status)) {
-               printf("Bad binding string %s\n", binding);
                ret = False;
                goto failed;
        }
@@ -1345,20 +1591,14 @@ BOOL torture_rpc_samlogon(void)
         * with INTERNAL_ERROR */
 
        b->flags &= ~DCERPC_AUTH_OPTIONS;
-       b->flags |= DCERPC_SCHANNEL_WORKSTATION | DCERPC_SIGN | DCERPC_SCHANNEL_128;
-
-       cli_credentials_set_workstation(credentials, TEST_MACHINE_NAME, CRED_SPECIFIED);
-       cli_credentials_set_domain(credentials, lp_workgroup(), CRED_SPECIFIED);
-       cli_credentials_set_username(credentials, test_machine_account, CRED_SPECIFIED);
-       cli_credentials_set_password(credentials, machine_password, CRED_SPECIFIED);
+       b->flags |= DCERPC_SCHANNEL | DCERPC_SIGN | DCERPC_SCHANNEL_128;
 
        status = dcerpc_pipe_connect_b(mem_ctx, &p, b, 
-                                      DCERPC_NETLOGON_UUID,
-                                      DCERPC_NETLOGON_VERSION,
-                                      credentials);
+                                      &ndr_table_netlogon,
+                                      machine_credentials, NULL);
 
        if (!NT_STATUS_IS_OK(status)) {
-               printf("RPC pipe connect as domain member failed: %s\n", nt_errstr(status));
+               d_printf("RPC pipe connect as domain member failed: %s\n", nt_errstr(status));
                ret = False;
                goto failed;
        }
@@ -1369,55 +1609,240 @@ BOOL torture_rpc_samlogon(void)
                goto failed;
        }
 
-       for (ci = 0; ci < ARRAY_SIZE(usercreds); ci++) {
-               
-               if (!test_InteractiveLogon(p, mem_ctx, creds,
-                                          usercreds[ci].domain,
-                                          usercreds[ci].username,
-                                          usercreds[ci].password)) {
-                       ret = False;
-               }
+       {
                
-               if (usercreds[ci].network_login) {
-                       if (!test_SamLogon(p, mem_ctx, creds, 
-                                          usercreds[ci].domain,
-                                          usercreds[ci].username,
-                                          usercreds[ci].password,
-                                          0)) {
-                               ret = False;
+               struct {
+                       const char *comment;
+                       const char *domain;
+                       const char *username;
+                       const char *password;
+                       BOOL network_login;
+                       NTSTATUS expected_interactive_error;
+                       NTSTATUS expected_network_error;
+                       uint32_t parameter_control;
+                       BOOL old_password; /* Allow an old password to be accepted or rejected without error, as well as session key bugs */
+               } usercreds[] = {
+                       {
+                               .comment       = "domain\\user",
+                               .domain        = cli_credentials_get_domain(cmdline_credentials),
+                               .username      = cli_credentials_get_username(cmdline_credentials),
+                               .password      = cli_credentials_get_password(cmdline_credentials),
+                               .network_login = True,
+                               .expected_interactive_error = NT_STATUS_OK,
+                               .expected_network_error     = NT_STATUS_OK
+                       },
+                       {
+                               .comment       = "realm\\user",
+                               .domain        = cli_credentials_get_realm(cmdline_credentials),
+                               .username      = cli_credentials_get_username(cmdline_credentials),
+                               .password      = cli_credentials_get_password(cmdline_credentials),
+                               .network_login = True,
+                               .expected_interactive_error = NT_STATUS_OK,
+                               .expected_network_error     = NT_STATUS_OK
+                       },
+                       {
+                               .comment       = "user@domain",
+                               .domain        = NULL,
+                               .username      = talloc_asprintf(mem_ctx, 
+                                               "%s@%s", 
+                                               cli_credentials_get_username(cmdline_credentials),
+                                               cli_credentials_get_domain(cmdline_credentials)
+                                       ),
+                               .password      = cli_credentials_get_password(cmdline_credentials),
+                               .network_login = False, /* works for some things, but not NTLMv2.  Odd */
+                               .expected_interactive_error = NT_STATUS_OK,
+                               .expected_network_error     = NT_STATUS_OK
+                       },
+                       {
+                               .comment       = "user@realm",
+                               .domain        = NULL,
+                               .username      = talloc_asprintf(mem_ctx, 
+                                               "%s@%s", 
+                                               cli_credentials_get_username(cmdline_credentials),
+                                               cli_credentials_get_realm(cmdline_credentials)
+                                       ),
+                               .password      = cli_credentials_get_password(cmdline_credentials),
+                               .network_login = True,
+                               .expected_interactive_error = NT_STATUS_OK,
+                               .expected_network_error     = NT_STATUS_OK
+                       },
+                       {
+                               .comment      = "machine domain\\user",
+                               .domain       = cli_credentials_get_domain(machine_credentials),
+                               .username     = cli_credentials_get_username(machine_credentials),
+                               .password     = cli_credentials_get_password(machine_credentials),
+                               .network_login = True,
+                               .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
+                               .parameter_control = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
+                       },
+                       {
+                               .comment      = "machine domain\\user",
+                               .domain       = cli_credentials_get_domain(machine_credentials),
+                               .username     = cli_credentials_get_username(machine_credentials),
+                               .password     = cli_credentials_get_password(machine_credentials),
+                               .network_login = True,
+                               .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
+                               .expected_network_error = NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
+                       },
+                       {
+                               .comment       = "machine realm\\user",
+                               .domain        = cli_credentials_get_realm(machine_credentials),
+                               .username      = cli_credentials_get_username(machine_credentials),
+                               .password      = cli_credentials_get_password(machine_credentials),
+                               .network_login = True,
+                               .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
+                               .parameter_control = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
+                       },
+                       {
+                               .comment       = "machine user@domain",
+                               .domain        = NULL,
+                               .username      = talloc_asprintf(mem_ctx, 
+                                                               "%s@%s", 
+                                                               cli_credentials_get_username(machine_credentials),
+                                                               cli_credentials_get_domain(machine_credentials)
+                                       ), 
+                               .password      = cli_credentials_get_password(machine_credentials),
+                               .network_login = False, /* works for some things, but not NTLMv2.  Odd */
+                               .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
+                               .parameter_control = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
+                       },
+                       {
+                               .comment       = "machine user@realm",
+                               .domain        = NULL,
+                               .username      = talloc_asprintf(mem_ctx, 
+                                                               "%s@%s", 
+                                                               cli_credentials_get_username(machine_credentials),
+                                                               cli_credentials_get_realm(machine_credentials)
+                                       ),
+                               .password      = cli_credentials_get_password(machine_credentials),
+                               .network_login = True,
+                               .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
+                               .parameter_control = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
+                       },
+                       {       
+                               .comment       = "test user (long pw): domain\\user",
+                               .domain        = userdomain,
+                               .username      = TEST_USER_NAME,
+                               .password      = user_password,
+                               .network_login = True,
+                               .expected_interactive_error = NT_STATUS_OK,
+                               .expected_network_error     = NT_STATUS_OK
+                       },
+                       {
+                               .comment       = "test user (long pw): user@realm", 
+                               .domain        = NULL,
+                               .username      = talloc_asprintf(mem_ctx, 
+                                                                "%s@%s", 
+                                                                TEST_USER_NAME,
+                                                                lp_realm()),
+                               .password      = user_password,
+                               .network_login = True,
+                               .expected_interactive_error = NT_STATUS_OK,
+                               .expected_network_error     = NT_STATUS_OK
+                       },
+                       {
+                               .comment       = "test user (long pw): user@domain",
+                               .domain        = NULL,
+                               .username      = talloc_asprintf(mem_ctx, 
+                                                                "%s@%s", 
+                                                                TEST_USER_NAME,
+                                                                userdomain),
+                               .password      = user_password,
+                               .network_login = False, /* works for some things, but not NTLMv2.  Odd */
+                               .expected_interactive_error = NT_STATUS_OK,
+                               .expected_network_error     = NT_STATUS_OK
+                       },
+                       /* Oddball, can we use the old password ? */
+                       {       
+                               .comment       = "test user: user\\domain OLD PASSWORD",
+                               .domain        = userdomain,
+                               .username      = TEST_USER_NAME,
+                               .password      = old_user_password,
+                               .network_login = True,
+                               .expected_interactive_error = NT_STATUS_WRONG_PASSWORD,
+                               .expected_network_error     = NT_STATUS_OK,
+                               .old_password  = True
+                       },
+                       {       
+                               .comment       = "test user (wong workstation): domain\\user",
+                               .domain        = userdomain,
+                               .username      = TEST_USER_NAME_WRONG_WKS,
+                               .password      = user_password_wrong_wks,
+                               .network_login = True,
+                               .expected_interactive_error = NT_STATUS_INVALID_WORKSTATION,
+                               .expected_network_error     = NT_STATUS_INVALID_WORKSTATION
                        }
-               }
-       }
-
-       for (i=0; i < ARRAY_SIZE(credential_flags); i++) {
+               };
                
+               /* Try all the tests for different username forms */
                for (ci = 0; ci < ARRAY_SIZE(usercreds); ci++) {
-                       
+               
                        if (!test_InteractiveLogon(p, mem_ctx, creds,
+                                                  usercreds[ci].comment,
+                                                  TEST_MACHINE_NAME,
                                                   usercreds[ci].domain,
                                                   usercreds[ci].username,
-                                                  usercreds[ci].password)) {
+                                                  usercreds[ci].password,
+                                                  usercreds[ci].parameter_control,
+                                                  usercreds[ci].expected_interactive_error)) {
                                ret = False;
                        }
-                       
+               
                        if (usercreds[ci].network_login) {
                                if (!test_SamLogon(p, mem_ctx, creds, 
+                                                  usercreds[ci].comment,
                                                   usercreds[ci].domain,
                                                   usercreds[ci].username,
                                                   usercreds[ci].password,
+                                                  usercreds[ci].parameter_control,
+                                                  usercreds[ci].expected_network_error,
+                                                  usercreds[ci].old_password,
+                                                  0)) {
+                                       ret = False;
+                               }
+                       }
+               }
+
+               /* Using the first username form, try the different
+                * credentials flag setups, on only one of the tests (checks
+                * session key encryption) */
+
+               for (i=0; i < ARRAY_SIZE(credential_flags); i++) {
+                       /* TODO:  Somehow we lost setting up the different credential flags here! */
+
+                       if (!test_InteractiveLogon(p, mem_ctx, creds,
+                                                  usercreds[0].comment,
+                                                  TEST_MACHINE_NAME,
+                                                  usercreds[0].domain,
+                                                  usercreds[0].username,
+                                                  usercreds[0].password,
+                                                  usercreds[0].parameter_control,
+                                                  usercreds[0].expected_interactive_error)) {
+                               ret = False;
+                       }
+               
+                       if (usercreds[0].network_login) {
+                               if (!test_SamLogon(p, mem_ctx, creds,
+                                                  usercreds[0].comment,
+                                                  usercreds[0].domain,
+                                                  usercreds[0].username,
+                                                  usercreds[0].password,
+                                                  usercreds[0].parameter_control,
+                                                  usercreds[0].expected_network_error,
+                                                  usercreds[0].old_password,
                                                   1)) {
                                        ret = False;
                                }
                        }
                }
-       }
 
+       }
 failed:
        talloc_free(mem_ctx);
 
        torture_leave_domain(join_ctx);
-#if 0
        torture_leave_domain(user_ctx);
-#endif
+       torture_leave_domain(user_ctx_wrong_wks);
+       torture_leave_domain(user_ctx_wrong_time);
        return ret;
 }