BOOL creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRED *cred_out) { BOOL ret; struct dcinfo tmp_dc = *dc; /* Do all operations on a temporary copy of the dc, which we throw away if the checks fail. */ tmp_dc.sequence = received_cred->timestamp.time; creds_step(&tmp_dc); /* Create the outgoing credentials */ cred_out->timestamp.time = tmp_dc.sequence + 1; cred_out->challenge = tmp_dc.srv_chal; creds_reseed(&tmp_dc); ret = creds_server_check(&tmp_dc, &received_cred->challenge); if (!ret) { return False; } /* creds step succeeded - replace the current creds. */ *dc = tmp_dc; return True; }
NTSTATUS creds_server_step_check(struct creds_CredentialState *creds, struct netr_Authenticator *received_authenticator, struct netr_Authenticator *return_authenticator) { if (!received_authenticator || !return_authenticator) { return NT_STATUS_INVALID_PARAMETER; } if (!creds) { return NT_STATUS_ACCESS_DENIED; } /* TODO: this may allow the a replay attack on a non-signed connection. Should we check that this is increasing? */ creds->sequence = received_authenticator->timestamp; creds_step(creds); if (creds_server_check(creds, &received_authenticator->cred)) { return_authenticator->cred = creds->server; return_authenticator->timestamp = creds->sequence; return NT_STATUS_OK; } else { ZERO_STRUCTP(return_authenticator); return NT_STATUS_ACCESS_DENIED; } }