From eed0c4f6c9aac5a260f65c05cc809bf5f72cf210 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 6 Apr 2009 22:53:01 +1000 Subject: [PATCH] Rework netlogon credentials for the top level This makes constructor functions that return the allocated structure, rather than having the caller pass them in, and makes the server init function also check the first credential. The rename of creds_ to netlogon_creds should make it more clear what this code works with. Andrew Bartlett --- libcli/auth/credentials.c | 186 ++++++++++++++++++++++++++++++++-------------- libcli/auth/credentials.h | 3 +- 2 files changed, 130 insertions(+), 59 deletions(-) diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c index 959c1ba68e5..dc84ffb4745 100644 --- a/libcli/auth/credentials.c +++ b/libcli/auth/credentials.c @@ -30,10 +30,10 @@ this call is made after the netr_ServerReqChallenge call */ -static void creds_init_64bit(struct creds_CredentialState *creds, - const struct netr_Credential *client_challenge, - const struct netr_Credential *server_challenge, - const struct samr_Password *machine_password) +static void netlogon_creds_init_64bit(struct netlogon_creds_CredentialState *creds, + const struct netr_Credential *client_challenge, + const struct netr_Credential *server_challenge, + const struct samr_Password *machine_password) { uint32_t sum[2]; uint8_t sum2[8]; @@ -59,10 +59,10 @@ static void creds_init_64bit(struct creds_CredentialState *creds, this call is made after the netr_ServerReqChallenge call */ -static void creds_init_128bit(struct creds_CredentialState *creds, - const struct netr_Credential *client_challenge, - const struct netr_Credential *server_challenge, - const struct samr_Password *machine_password) +static void netlogon_creds_init_128bit(struct netlogon_creds_CredentialState *creds, + const struct netr_Credential *client_challenge, + const struct netr_Credential *server_challenge, + const struct samr_Password *machine_password) { unsigned char zero[4], tmp[16]; HMACMD5Context ctx; @@ -95,7 +95,7 @@ static void creds_init_128bit(struct creds_CredentialState *creds, step the credentials to the next element in the chain, updating the current client and server credentials and the seed */ -static void creds_step(struct creds_CredentialState *creds) +static void netlogon_creds_step(struct netlogon_creds_CredentialState *creds) { struct netr_Credential time_cred; @@ -130,7 +130,7 @@ static void creds_step(struct creds_CredentialState *creds) /* DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key */ -void creds_des_encrypt_LMKey(struct creds_CredentialState *creds, struct netr_LMSessionKey *key) +void netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key) { struct netr_LMSessionKey tmp; des_crypt56(tmp.key, key->key, creds->session_key, 1); @@ -140,7 +140,7 @@ void creds_des_encrypt_LMKey(struct creds_CredentialState *creds, struct netr_LM /* DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key */ -void creds_des_decrypt_LMKey(struct creds_CredentialState *creds, struct netr_LMSessionKey *key) +void netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key) { struct netr_LMSessionKey tmp; des_crypt56(tmp.key, key->key, creds->session_key, 0); @@ -150,7 +150,7 @@ void creds_des_decrypt_LMKey(struct creds_CredentialState *creds, struct netr_LM /* DES encrypt a 16 byte password buffer using the session key */ -void creds_des_encrypt(struct creds_CredentialState *creds, struct samr_Password *pass) +void netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass) { struct samr_Password tmp; des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1); @@ -160,7 +160,7 @@ void creds_des_encrypt(struct creds_CredentialState *creds, struct samr_Password /* DES decrypt a 16 byte password buffer using the session key */ -void creds_des_decrypt(struct creds_CredentialState *creds, struct samr_Password *pass) +void netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass) { struct samr_Password tmp; des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0); @@ -170,7 +170,7 @@ void creds_des_decrypt(struct creds_CredentialState *creds, struct samr_Password /* ARCFOUR encrypt/decrypt a password buffer using the session key */ -void creds_arcfour_crypt(struct creds_CredentialState *creds, uint8_t *data, size_t len) +void netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len) { DATA_BLOB session_key = data_blob(creds->session_key, 16); @@ -188,30 +188,69 @@ next comes the client specific functions initialise the credentials chain and return the first client credentials */ -void creds_client_init(struct creds_CredentialState *creds, - const struct netr_Credential *client_challenge, - const struct netr_Credential *server_challenge, - const struct samr_Password *machine_password, - struct netr_Credential *initial_credential, - uint32_t negotiate_flags) + +struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx, + const char *client_account, + const char *client_computer_name, + const struct netr_Credential *client_challenge, + const struct netr_Credential *server_challenge, + const struct samr_Password *machine_password, + struct netr_Credential *initial_credential, + uint32_t negotiate_flags) { + struct netlogon_creds_CredentialState *creds = talloc(mem_ctx, struct netlogon_creds_CredentialState); + + if (!creds) { + return NULL; + } + creds->sequence = time(NULL); creds->negotiate_flags = negotiate_flags; + creds->computer_name = talloc_strdup(creds, client_computer_name); + if (!creds->computer_name) { + talloc_free(creds); + return NULL; + } + creds->account_name = talloc_strdup(creds, client_account); + if (!creds->account_name) { + talloc_free(creds); + return NULL; + } + dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data)); dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data)); dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash)); if (negotiate_flags & NETLOGON_NEG_128BIT) { - creds_init_128bit(creds, client_challenge, server_challenge, machine_password); + netlogon_creds_init_128bit(creds, client_challenge, server_challenge, machine_password); } else { - creds_init_64bit(creds, client_challenge, server_challenge, machine_password); + netlogon_creds_init_64bit(creds, client_challenge, server_challenge, machine_password); } dump_data_pw("Session key", creds->session_key, 16); dump_data_pw("Credential ", creds->client.data, 8); *initial_credential = creds->client; + return creds; +} + +/* + initialise the credentials structure with only a session key. The caller better know what they are doing! + */ + +struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx, + const uint8_t session_key[16]) +{ + struct netlogon_creds_CredentialState *creds = talloc(mem_ctx, struct netlogon_creds_CredentialState); + + if (!creds) { + return NULL; + } + + memcpy(creds->session_key, session_key, 16); + + return creds; } /* @@ -221,11 +260,11 @@ void creds_client_init(struct creds_CredentialState *creds, produce the next authenticator in the sequence ready to send to the server */ -void creds_client_authenticator(struct creds_CredentialState *creds, +void netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds, struct netr_Authenticator *next) { creds->sequence += 2; - creds_step(creds); + netlogon_creds_step(creds); next->cred = creds->client; next->timestamp = creds->sequence; @@ -234,7 +273,7 @@ void creds_client_authenticator(struct creds_CredentialState *creds, /* check that a credentials reply from a server is correct */ -bool creds_client_check(struct creds_CredentialState *creds, +bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds, const struct netr_Credential *received_credentials) { if (!received_credentials || @@ -252,33 +291,10 @@ next comes the server specific functions ******************************************************************/ /* - initialise the credentials chain and return the first server - credentials -*/ -void creds_server_init(struct creds_CredentialState *creds, - const struct netr_Credential *client_challenge, - const struct netr_Credential *server_challenge, - const struct samr_Password *machine_password, - struct netr_Credential *initial_credential, - uint32_t negotiate_flags) -{ - if (negotiate_flags & NETLOGON_NEG_128BIT) { - creds_init_128bit(creds, client_challenge, server_challenge, - machine_password); - } else { - creds_init_64bit(creds, client_challenge, server_challenge, - machine_password); - } - - *initial_credential = creds->server; - creds->negotiate_flags = negotiate_flags; -} - -/* check that a credentials reply from a server is correct */ -bool creds_server_check(const struct creds_CredentialState *creds, - const struct netr_Credential *received_credentials) +static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds, + const struct netr_Credential *received_credentials) { if (memcmp(received_credentials->data, creds->client.data, 8) != 0) { DEBUG(2,("credentials check failed\n")); @@ -289,7 +305,62 @@ bool creds_server_check(const struct creds_CredentialState *creds, return true; } -NTSTATUS creds_server_step_check(struct creds_CredentialState *creds, +/* + initialise the credentials chain and return the first server + credentials +*/ +struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx, + const char *client_account, + const char *client_computer_name, + uint16_t secure_channel_type, + const struct netr_Credential *client_challenge, + const struct netr_Credential *server_challenge, + const struct samr_Password *machine_password, + struct netr_Credential *credentials_in, + struct netr_Credential *credentials_out, + uint32_t negotiate_flags) +{ + + struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState); + + if (!creds) { + return NULL; + } + + creds->negotiate_flags = negotiate_flags; + + creds->computer_name = talloc_strdup(creds, client_computer_name); + if (!creds->computer_name) { + talloc_free(creds); + return NULL; + } + creds->account_name = talloc_strdup(creds, client_account); + if (!creds->account_name) { + talloc_free(creds); + return NULL; + } + + if (negotiate_flags & NETLOGON_NEG_128BIT) { + netlogon_creds_init_128bit(creds, client_challenge, server_challenge, + machine_password); + } else { + netlogon_creds_init_64bit(creds, client_challenge, server_challenge, + machine_password); + } + + /* And before we leak information about the machine account + * password, check that they got the first go right */ + if (!netlogon_creds_server_check_internal(creds, credentials_in)) { + talloc_free(creds); + return NULL; + } + + *credentials_out = creds->server; + + return creds; +} + +NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds, struct netr_Authenticator *received_authenticator, struct netr_Authenticator *return_authenticator) { @@ -304,8 +375,8 @@ NTSTATUS creds_server_step_check(struct creds_CredentialState *creds, /* 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)) { + netlogon_creds_step(creds); + if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) { return_authenticator->cred = creds->server; return_authenticator->timestamp = creds->sequence; return NT_STATUS_OK; @@ -315,7 +386,7 @@ NTSTATUS creds_server_step_check(struct creds_CredentialState *creds, } } -void creds_decrypt_samlogon(struct creds_CredentialState *creds, +void netlogon_creds_decrypt_samlogon(struct netlogon_creds_CredentialState *creds, uint16_t validation_level, union netr_Validation *validation) { @@ -353,22 +424,23 @@ void creds_decrypt_samlogon(struct creds_CredentialState *creds, } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) { if (memcmp(base->key.key, zeros, sizeof(base->key.key)) != 0) { - creds_arcfour_crypt(creds, + netlogon_creds_arcfour_crypt(creds, base->key.key, sizeof(base->key.key)); } if (memcmp(base->LMSessKey.key, zeros, sizeof(base->LMSessKey.key)) != 0) { - creds_arcfour_crypt(creds, + netlogon_creds_arcfour_crypt(creds, base->LMSessKey.key, sizeof(base->LMSessKey.key)); } } else { if (memcmp(base->LMSessKey.key, zeros, sizeof(base->LMSessKey.key)) != 0) { - creds_des_decrypt_LMKey(creds, + netlogon_creds_des_decrypt_LMKey(creds, &base->LMSessKey); } } } + diff --git a/libcli/auth/credentials.h b/libcli/auth/credentials.h index a3dd3630648..b84b902fa0b 100644 --- a/libcli/auth/credentials.h +++ b/libcli/auth/credentials.h @@ -21,7 +21,7 @@ #include "librpc/gen_ndr/netlogon.h" -struct creds_CredentialState { +struct netlogon_creds_CredentialState { uint32_t negotiate_flags; uint8_t session_key[16]; uint32_t sequence; @@ -29,7 +29,6 @@ struct creds_CredentialState { struct netr_Credential client; struct netr_Credential server; uint16_t secure_channel_type; - const char *domain; const char *computer_name; const char *account_name; struct dom_sid *sid; -- 2.11.4.GIT