another big improvement in the credentials API. I think it now
authorAndrew Tridgell <tridge@samba.org>
Tue, 2 Dec 2003 02:15:33 +0000 (02:15 +0000)
committerAndrew Tridgell <tridge@samba.org>
Tue, 2 Dec 2003 02:15:33 +0000 (02:15 +0000)
actually makes sense, and as a nice side effect it matches the debug
output of the w2k3 netlogon.log

source/libcli/auth/credentials.c
source/librpc/idl/netlogon.idl
source/torture/rpc/netlogon.c

index 1749037e8f65345adc78782898f50f798dbaa137..5814053d5fb2c0d822f3be07e456e19bda100a09 100644 (file)
 
   this call is made after the netr_ServerReqChallenge call
 */
-void creds_init(struct netr_CredentialState *creds,
-               const struct netr_Credential *client_challenge,
-               const struct netr_Credential *server_challenge,
-               const uint8 machine_password[16],
-               struct netr_Credential *initial_creds)
+static void creds_init(struct netr_CredentialState *creds,
+                      const struct netr_Credential *client_challenge,
+                      const struct netr_Credential *server_challenge,
+                      const uint8 machine_password[16])
 {
        struct netr_Credential time_cred;
        uint32 sum[2];
@@ -46,36 +45,82 @@ void creds_init(struct netr_CredentialState *creds,
 
        cred_hash1(creds->session_key, sum2, machine_password);
 
-       creds->sequence = 0;
+       creds->sequence = time(NULL);
 
        SIVAL(time_cred.data, 0, IVAL(client_challenge->data, 0));
        SIVAL(time_cred.data, 4, IVAL(client_challenge->data, 4));
+       cred_hash2(creds->client.data, time_cred.data, creds->session_key);
 
-       cred_hash2(creds->cred2.data, time_cred.data, creds->session_key);
+       SIVAL(time_cred.data, 0, IVAL(server_challenge->data, 0));
+       SIVAL(time_cred.data, 4, IVAL(server_challenge->data, 4));
+       cred_hash2(creds->server.data, time_cred.data, creds->session_key);
 
-       creds->cred1 = *server_challenge;
+       creds->seed = creds->client;
+}
+
+
+/*
+  step the credentials to the next element in the chain
+*/
+static void creds_step(struct netr_CredentialState *creds)
+{
+       struct netr_Credential time_cred;
+
+       creds->sequence += 2;
+
+       DEBUG(5,("\tseed        %08x:%08x\n", 
+                IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
+
+       SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
+       SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
+
+       DEBUG(5,("\tseed+time   %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
+
+       cred_hash2(creds->client.data, time_cred.data, creds->session_key);
+
+       DEBUG(5,("\tCLIENT      %08x:%08x\n", 
+                IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
+
+       SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
+       SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
+
+       DEBUG(5,("\tseed+time+1 %08x:%08x\n", 
+                IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
+
+       cred_hash2(creds->server.data, time_cred.data, creds->session_key);
 
-       *initial_creds = creds->cred2;
+       DEBUG(5,("\tSERVER      %08x:%08x\n", 
+                IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
+
+       creds->seed = time_cred;
 }
 
 
 /*
-  check that a credentials reply is correct
+  initialise the credentials chain and return the first client
+  credentials
 */
-BOOL creds_check(struct netr_CredentialState *creds,
-                const struct netr_Credential *received_credentials)
+void creds_client_init(struct netr_CredentialState *creds,
+                      const struct netr_Credential *client_challenge,
+                      const struct netr_Credential *server_challenge,
+                      const uint8 machine_password[16],
+                      struct netr_Credential *initial_credential)
 {
-       struct netr_Credential cred2, time_cred;
-       uint32 sequence = creds->sequence?creds->sequence+1:0;
+       creds_init(creds, client_challenge, server_challenge, machine_password);
+
+       *initial_credential = creds->client;
+}
 
-       SIVAL(time_cred.data, 0, IVAL(creds->cred1.data, 0) + sequence);
-       SIVAL(time_cred.data, 4, IVAL(creds->cred1.data, 4));
-       cred_hash2(cred2.data, time_cred.data, creds->session_key);
-       if (memcmp(received_credentials->data, cred2.data, 8) != 0) {
+/*
+  check that a credentials reply from a server is correct
+*/
+BOOL creds_client_check(struct netr_CredentialState *creds,
+                       const struct netr_Credential *received_credentials)
+{
+       if (memcmp(received_credentials->data, creds->server.data, 8) != 0) {
                DEBUG(2,("credentials check failed\n"));
                return False;
        }
-
        return True;
 }
 
@@ -83,30 +128,12 @@ BOOL creds_check(struct netr_CredentialState *creds,
   produce the next authenticator in the sequence ready to send to 
   the server
 */
-void creds_authenticator(struct netr_CredentialState *creds,
-                        struct netr_Authenticator *next)
+void creds_client_authenticator(struct netr_CredentialState *creds,
+                               struct netr_Authenticator *next)
 {
-       struct netr_Credential cred2;
-       struct netr_Credential time_cred;
-
-       if (creds->sequence == 0) {
-               creds->sequence = time(NULL);
-       }
-
-       /* this step size is quite arbitrary - the client can choose
-          any sequence number it likes */
-       creds->sequence += 2;
-
-       creds->cred1 = creds->cred2;
-
-       SIVAL(time_cred.data, 0, IVAL(creds->cred2.data, 0) + creds->sequence);
-       SIVAL(time_cred.data, 4, IVAL(creds->cred2.data, 4));
-
-       cred_hash2(cred2.data, time_cred.data, creds->session_key);
-
-       creds->cred2 = cred2;
+       creds_step(creds);
 
-       next->cred = creds->cred2;
+       next->cred = creds->client;
        next->timestamp = creds->sequence;
 }
 
@@ -114,7 +141,7 @@ void creds_authenticator(struct netr_CredentialState *creds,
 /*
   encrypt a 16 byte password buffer using the session key
 */
-void creds_encrypt(struct netr_CredentialState *creds, struct netr_Password *pass)
+void creds_client_encrypt(struct netr_CredentialState *creds, struct netr_Password *pass)
 {
        struct netr_Password tmp;
        cred_hash3(tmp.data, pass->data, creds->session_key, 1);
index 6dd7ae3fe5543346b176f2431be018291c54fe5b..5d30b51157d11ffd616d4e7ea481a501d657c337 100644 (file)
@@ -71,8 +71,9 @@ interface netlogon
        typedef [flag(NDR_PAHEX)] struct {
                uint8 session_key[8];
                uint32 sequence;
-               netr_Credential cred1;
-               netr_Credential cred2;
+               netr_Credential seed;
+               netr_Credential client;
+               netr_Credential server;
        } netr_CredentialState;
 
        typedef struct {
@@ -229,6 +230,10 @@ interface netlogon
                [out] uint32 authoritative
                );
 
+
+       /*****************/
+       /* Function 0x03 */
+
        NTSTATUS netr_LogonSamLogoff(
                [in] unistr *server_name,
                [in] unistr *computer_name,
@@ -238,13 +243,22 @@ interface netlogon
                [in] [switch_is(logon_level)] netr_LogonLevel logon
                );
 
-       WERROR netr_ServerReqChallenge(
+
+
+       /*****************/
+       /* Function 0x04 */
+
+       NTSTATUS netr_ServerReqChallenge(
                [in]        unistr *server_name,
                [in]        unistr computer_name,
                [in][out]   netr_Credential credentials
                );
 
-       WERROR netr_ServerAuthenticate(
+
+       /*****************/
+       /* Function 0x05 */
+
+       NTSTATUS netr_ServerAuthenticate(
                [in]        unistr *server_name,
                [in]        unistr username,
                [in]        uint16 secure_challenge_type,
@@ -253,6 +267,9 @@ interface netlogon
                );
 
 
+       /*****************/
+       /* Function 0x06 */
+
        NTSTATUS netr_ServerPasswordSet(
                [in]  unistr *server_name,
                [in]  unistr username,
@@ -264,22 +281,28 @@ interface netlogon
                );
 
 #if 0
+
+       /*****************/
+       /* Function 0x07 */
+
        typedef struct {
                unistr *username;
-               netr_String dummy1;
-               netr_String dummy2;
-               netr_String dummy3;
-               netr_String dummy4;
-               uint32 dummy5;
-               uint32 dummy6;
-               uint32 dummy7;
-               uint32 dummy8;
+               netr_String unknown1;
+               netr_String unknown2;
+               netr_String unknown3;
+               netr_String unknown4;
+               uint32 unknown5;
+               uint32 unknown6;
+               uint32 unknown7;
+               uint32 unknown8;
        } DELTA_DELETE_USER;
+
        typedef struct {
                bool SensitiveDataFlag;
                uint32 DataLength;
                [size_is(DataLength)] uint8 *SensitiveData;
        } USER_PRIVATE_INFO;
+
        typedef struct {
                netr_String username;
                netr_String FullName;
@@ -310,15 +333,16 @@ interface netlogon
                USER_PRIVATE_INFO user_private_info;
                uint32 SecurityInformation;
                LSA_SECURITY_DESCRIPTOR sec_desc;
-               netr_String dummy1;
-               netr_String dummy2;
-               netr_String dummy3;
-               netr_String dummy4;
-               uint32 dummy5;
-               uint32 dummy6;
-               uint32 dummy7;
-               uint32 dummy8;
+               netr_String unknown1;
+               netr_String unknown2;
+               netr_String unknown3;
+               netr_String unknown4;
+               uint32 unknown5;
+               uint32 unknown6;
+               uint32 unknown7;
+               uint32 unknown8;
        } DELTA_USER;
+
        typedef struct {
                netr_String DomainName;
                netr_String OEMInfo;
@@ -331,72 +355,78 @@ interface netlogon
                NTTIME domain_create_time;
                uint32 SecurityInformation;
                LSA_SECURITY_DESCRIPTOR sec_desc;
-               netr_String dummy1;
-               netr_String dummy2;
-               netr_String dummy3;
-               netr_String dummy4;
-               uint32 dummy5;
-               uint32 dummy6;
-               uint32 dummy7;
-               uint32 dummy8;
+               netr_String unknown1;
+               netr_String unknown2;
+               netr_String unknown3;
+               netr_String unknown4;
+               uint32 unknown5;
+               uint32 unknown6;
+               uint32 unknown7;
+               uint32 unknown8;
        } DELTA_DOMAIN;
+
        typedef struct {
                netr_String groupname;
                GROUP_MEMBERSHIP group_membership;
                netr_String comment;
                uint32 SecurityInformation;
                LSA_SECURITY_DESCRIPTOR sec_desc;
-               netr_String dummy1;
-               netr_String dummy2;
-               netr_String dummy3;
-               netr_String dummy4;
-               uint32 dummy5;
-               uint32 dummy6;
-               uint32 dummy7;
-               uint32 dummy8;
+               netr_String unknown1;
+               netr_String unknown2;
+               netr_String unknown3;
+               netr_String unknown4;
+               uint32 unknown5;
+               uint32 unknown6;
+               uint32 unknown7;
+               uint32 unknown8;
        } DELTA_GROUP;
+
        typedef struct {
                netr_String OldName;
                netr_String NewName;
-               netr_String dummy1;
-               netr_String dummy2;
-               netr_String dummy3;
-               netr_String dummy4;
-               uint32 dummy5;
-               uint32 dummy6;
-               uint32 dummy7;
-               uint32 dummy8;
+               netr_String unknown1;
+               netr_String unknown2;
+               netr_String unknown3;
+               netr_String unknown4;
+               uint32 unknown5;
+               uint32 unknown6;
+               uint32 unknown7;
+               uint32 unknown8;
        } DELTA_RENAME;
+
        typedef struct {
                [size_is(num_rids)] uint32 *rids;
                [size_is(num_rids)] uint32 *attribs;
                uint32 num_rids;
-               uint32 dummy1;
-               uint32 dummy2;
-               uint32 dummy3;
-               uint32 dummy4;
+               uint32 unknown1;
+               uint32 unknown2;
+               uint32 unknown3;
+               uint32 unknown4;
        } DELTA_GROUP_MEMBER;
+
        typedef struct {
                netr_String alias_name;
                uint32 rid;
                uint32 SecurityInformation;
                LSA_SECURITY_DESCRIPTOR sec_desc;
-               netr_String dummy1;
-               netr_String dummy2;
-               netr_String dummy3;
-               netr_String dummy4;
-               uint32 dummy5;
-               uint32 dummy6;
-               uint32 dummy7;
-               uint32 dummy8;
+               netr_String unknown1;
+               netr_String unknown2;
+               netr_String unknown3;
+               netr_String unknown4;
+               uint32 unknown5;
+               uint32 unknown6;
+               uint32 unknown7;
+               uint32 unknown8;
        } DELTA_ALIAS;
+
        typedef struct {
                 SID_ARRAY sids;
-               uint32 dummy1;
-               uint32 dummy2;
-               uint32 dummy3;
-               uint32 dummy4;
+               uint32 unknown1;
+               uint32 unknown2;
+               uint32 unknown3;
+               uint32 unknown4;
        } DELTA_ALIAS_MEMBER;
+
        typedef struct {
                uint32 pagedpoollimit;
                uint32 nonpagedpoollimit;
@@ -405,6 +435,7 @@ interface netlogon
                uint32 pagefilelimit;
                NTTIME timelimit;
        } QUOTA_LIMITS;
+
        typedef struct {
                uint32 maxlogsize;
                NTTIME auditretentionperiod;
@@ -418,30 +449,32 @@ interface netlogon
                NTTIME db_create_time;
                uint32 SecurityInformation;
                LSA_SECURITY_DESCRIPTOR sec_desc;
-               netr_String dummy1;
-               netr_String dummy2;
-               netr_String dummy3;
-               netr_String dummy4;
-               uint32 dummy5;
-               uint32 dummy6;
-               uint32 dummy7;
-               uint32 dummy8;
+               netr_String unknown1;
+               netr_String unknown2;
+               netr_String unknown3;
+               netr_String unknown4;
+               uint32 unknown5;
+               uint32 unknown6;
+               uint32 unknown7;
+               uint32 unknown8;
        } DELTA_POLICY;
+
        typedef struct {
                netr_String DomainName;
                uint32 num_controllers;
                [size_is(num_controllers)] netr_String *controller_names;
                uint32 SecurityInformation;
                LSA_SECURITY_DESCRIPTOR sec_desc;
-               netr_String dummy1;
-               netr_String dummy2;
-               netr_String dummy3;
-               netr_String dummy4;
-               uint32 dummy5;
-               uint32 dummy6;
-               uint32 dummy7;
-               uint32 dummy8;
+               netr_String unknown1;
+               netr_String unknown2;
+               netr_String unknown3;
+               netr_String unknown4;
+               uint32 unknown5;
+               uint32 unknown6;
+               uint32 unknown7;
+               uint32 unknown8;
        } DELTA_TRUSTED_DOMAINS;
+
        typedef struct {
                uint32 privilegeentries;
                uint32 provolegecontrol;
@@ -450,20 +483,22 @@ interface netlogon
                QUOTALIMITS quotalimits;
                uint32 SecurityInformation;
                LSA_SECURITY_DESCRIPTOR sec_desc;
-               netr_String dummy1;
-               netr_String dummy2;
-               netr_String dummy3;
-               netr_String dummy4;
-               uint32 dummy5;
-               uint32 dummy6;
-               uint32 dummy7;
-               uint32 dummy8;
+               netr_String unknown1;
+               netr_String unknown2;
+               netr_String unknown3;
+               netr_String unknown4;
+               uint32 unknown5;
+               uint32 unknown6;
+               uint32 unknown7;
+               uint32 unknown8;
        } DELTA_ACCOUNTS;
+
        typedef struct {
                uint32 len;
                uint32 maxlen;
                [size_is(maxlen)][length_is(len)] uint8 *cipher_data;
        } CIPHER_VALUE;
+
        typedef struct {
                CIPHER_VALUE current_cipher;
                NTTIME current_cipher_set_time;
@@ -471,15 +506,16 @@ interface netlogon
                NTTIME old_cipher_set_time;
                uint32 SecurityInformation;
                LSA_SECURITY_DESCRIPTOR sec_desc;
-               netr_String dummy1;
-               netr_String dummy2;
-               netr_String dummy3;
-               netr_String dummy4;
-               uint32 dummy5;
-               uint32 dummy6;
-               uint32 dummy7;
-               uint32 dummy8;
+               netr_String unknown1;
+               netr_String unknown2;
+               netr_String unknown3;
+               netr_String unknown4;
+               uint32 unknown5;
+               uint32 unknown6;
+               uint32 unknown7;
+               uint32 unknown8;
        } DELTA_SECRET;
+
        typedef struct {
                uint32 low_value;
                uint32 high_value;
@@ -527,15 +563,19 @@ interface netlogon
                [case(20)] uint32 rid;
                [case(21)] uint32 rid;
        } DELTA_ID_UNION;
+
        typedef struct {
                uint16 delta_type;
                DELTA_ID_UNION delta_id_union;
                DELTA_UNION delta_union;
        } DELTA_ENUM;
+
        typedef struct {
                uint32 num_deltas;
                [size_is(num_deltas)] DELTA_ENUM *delta_enum;
        } DELTA_ENUM_ARRAY;
+
+
        WERROR netr_DatabaseDeltas(
                [in][string][ref] wchar_t *logonserver, # REF!!!
                [in][string][ref] wchar_t *computername,
@@ -546,6 +586,11 @@ interface netlogon
                [in] uint32 preferredmaximumlength,
                [out] DELTA_ENUM_ARRAY *delta_enum_array
                );
+
+
+       /*****************/
+       /* Function 0x08 */
+
        WERROR netr_DatabaseSync(
                [in][string][ref] wchar_t *logonserver, # REF!!!
                [in][string][ref] wchar_t *computername,
@@ -556,11 +601,17 @@ interface netlogon
                [in] uint32 preferredmaximumlength,
                [out] DELTA_ENUM_ARRAY *delta_enum_array
                );
+
+
+       /*****************/
+       /* Function 0x09 */
+
        typedef struct {
                uint8 computer_name[16];
                uint32 timecreated;
                uint32 serial_number;
        } UAS_INFO_0;
+
        WERROR netr_AccountDeltas(
                [in][string] wchar_t *logonserver,
                [in][string][ref] wchar_t *computername,
@@ -574,6 +625,11 @@ interface netlogon
                [in][long] level,
                [in][long] buffersize,
                );
+
+
+       /*****************/
+       /* Function 0x0A */
+
        WERROR netr_AccountSync(
                [in][string] wchar_t *logonserver,
                [in][string][ref] wchar_t *computername,
@@ -588,21 +644,29 @@ interface netlogon
                [in][long] buffersize,
                [in][out][ref] UAS_INFO_0 recordid,
                );
+
+
+       /*****************/
+       /* Function 0x0B */
+
        WERROR netr_GetDcName(
                [in] unistr logon_server,
                [in] unistr *domainname,
                [out]unistr *dcname,
                };
+
        typedef struct {
                uint32 flags;
                uint32 pdc_connection_status;
        } NETLOGON_INFO_1;
+
        typedef struct {
                uint32 flags;
                uint32 pdc_connection_status;
                unistrtrusted_dc_name;
                uint32 tc_connection_status;
        } NETLOGON_INFO_2;
+
        typedef struct {
                uint32 flags;
                uint32 logon_attempts;
@@ -612,28 +676,45 @@ interface netlogon
                uint32 reserved;
                uint32 reserved;
        } NETLOGON_INFO_3;
+
        typedef [switch_type(long)] union {
                [case(1)]  NETLOGON_INFO_1 *i1;
                [case(2)]  NETLOGON_INFO_2 *i2;
                [case(3)]  NETLOGON_INFO_3 *i3;
        } CONTROL_QUERY_INFORMATION;
+
+
+       /*****************/
+       /* Function 0x0C */
+
        WERROR netr_LogonControl(
                [in][string] wchar_t *logonserver,
                [in] uint32 function_code,
                [in] uint32 level,
                [out][ref] CONTROL_QUERY_INFORMATION
                );
+
+
+       /*****************/
+       /* Function 0x0D */
+
        WERROR netr_GetAnyDCName(
                [in] unistr *logon_server,
                [in] unistr *domainname,
                [out]unistr *dcname,
                };
+
        typedef [switch_type(long)] union {
                [case(5)] unistr *unknown;
                [case(6)] unistr *unknown;
                [case(0xfffe)] uint32 unknown;
                [case(7)] unistry*unknown;
        } CONTROL_DATA_INFORMATION;
+
+
+       /*****************/
+       /* Function 0x0E */
+
        WERROR netr_LogonControl2(
                [in][string] wchar_t *logonserver,
                [in] uint32 function_code,
@@ -641,6 +722,11 @@ interface netlogon
                [in][ref] CONTROL_DATA_INFORMATION *data,
                [out][ref] CONTROL_QUERY_INFORMATION *query
                );
+
+
+       /*****************/
+       /* Function 0x0F */
+
        WERROR netr_ServerAuthenticate2(
                [in][string] wchar_t *logonserver,
                [in] unistr username,
@@ -650,6 +736,11 @@ interface netlogon
                [out][ref] CREDENTIAL *server_chal,
                [in][out][ref] uint32 *negotiate_flags,
                );
+
+
+       /*****************/
+       /* Function 0x10 */
+
        WERROR netr_DatabaseSync2(
                [in][string][ref] wchar_t *logonserver, # REF!!!
                [in][string][ref] wchar_t *computername,
@@ -661,6 +752,11 @@ interface netlogon
                [in] uint32 preferredmaximumlength,
                [out] DELTA_ENUM_ARRAY *delta_enum_array
                );
+
+
+       /*****************/
+       /* Function 0x11 */
+
        WERROR netr_DatabaseRedo(
                [in][string][ref] wchar_t *logonserver, # REF!!!
                [in][string][ref] wchar_t *computername,
@@ -670,6 +766,11 @@ interface netlogon
                [in] uint32 change_log_entry_size,
                [out] DELTA_ENUM_ARRAY *delta_enum_array
                );
+
+
+       /*****************/
+       /* Function 0x12 */
+
        WERROR netr_LogonControl2Ex(
                [in][string] wchar_t *logonserver,
                [in] uint32 function_code,
index bef658e92fb3daa6a0f29bfd23d73511ca4e2246..354a516884ef5f11deb55114624e9af257cf6b92 100644 (file)
@@ -94,8 +94,8 @@ static BOOL test_SetupCredentials(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
 
        E_md4hash(plain_pass, mach_pwd);
 
-       creds_init(creds, &r.in.credentials, &r.out.credentials, mach_pwd,
-                  &a.in.credentials);
+       creds_client_init(creds, &r.in.credentials, &r.out.credentials, mach_pwd,
+                         &a.in.credentials);
 
        a.in.server_name = NULL;
        a.in.username = talloc_asprintf(mem_ctx, "%s$", lp_netbios_name());
@@ -110,7 +110,7 @@ static BOOL test_SetupCredentials(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
                return False;
        }
 
-       if (!creds_check(creds, &a.out.credentials)) {
+       if (!creds_client_check(creds, &a.out.credentials)) {
                printf("Credential chaining failed\n");
                return False;
        }
@@ -152,7 +152,7 @@ static BOOL test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
 
        ZERO_STRUCT(auth2);
 
-       creds_authenticator(&creds, &auth);
+       creds_client_authenticator(&creds, &auth);
 
        r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
        r.in.workstation = lp_netbios_name();
@@ -170,7 +170,7 @@ static BOOL test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
                return False;
        }
 
-       if (!creds_check(&creds, &r.out.authenticator->cred)) {
+       if (!creds_client_check(&creds, &r.out.authenticator->cred)) {
                printf("Credential chaining failed\n");
        }
 
@@ -192,8 +192,6 @@ static BOOL test_SetPassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
                return False;
        }
 
-       creds_authenticator(&creds, &r.in.credential);
-
        r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
        r.in.username = talloc_asprintf(mem_ctx, "%s$", lp_netbios_name());
        r.in.secure_challenge_type = 2;
@@ -202,10 +200,12 @@ static BOOL test_SetPassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
        password = generate_random_str(8);
        E_md4hash(password, r.in.new_password.data);
 
-       creds_encrypt(&creds, &r.in.new_password);
+       creds_client_encrypt(&creds, &r.in.new_password);
 
        printf("Testing ServerPasswordSet on machine account\n");
 
+       creds_client_authenticator(&creds, &r.in.credential);
+
        status = dcerpc_netr_ServerPasswordSet(p, mem_ctx, &r);
        if (!NT_STATUS_IS_OK(status)) {
                printf("ServerPasswordSet - %s\n", nt_errstr(status));
@@ -216,7 +216,21 @@ static BOOL test_SetPassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
                printf("Failed to save machine password\n");
        }
 
-       if (!creds_check(&creds, &r.out.return_authenticator.cred)) {
+       if (!creds_client_check(&creds, &r.out.return_authenticator.cred)) {
+               printf("Credential chaining failed\n");
+       }
+
+       printf("Testing a second ServerPasswordSet on machine account\n");
+
+       creds_client_authenticator(&creds, &r.in.credential);
+
+       status = dcerpc_netr_ServerPasswordSet(p, mem_ctx, &r);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("ServerPasswordSet - %s\n", nt_errstr(status));
+               return False;
+       }
+
+       if (!creds_client_check(&creds, &r.out.return_authenticator.cred)) {
                printf("Credential chaining failed\n");
        }