From: Stefan Metzmacher Date: Tue, 16 Dec 2014 13:58:11 +0000 (+0000) Subject: auth/credentials: add cli_credentials_set_utf16_password() X-Git-Url: http://git.samba.org/?p=obnox%2Fsamba%2Fsamba-obnox.git;a=commitdiff_plain;h=826b0f761e07987fbe067badde665c3d1c99e821 auth/credentials: add cli_credentials_set_utf16_password() We need a way to initialize the cli_credentials from the raw utf16 blob, which might not be completely valid utf16, which means the conversion from CH_UTF16MUNGED to CH_UTF8 might loose information. This would result in an invalid nt_hash, when we convert back from CH_UTF8 to CH_UTF16LE. Bug: https://bugzilla.samba.org/show_bug.cgi?id=11016 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett --- diff --git a/auth/credentials/credentials.c b/auth/credentials/credentials.c index 78b59556eae..a9e4fc864d4 100644 --- a/auth/credentials/credentials.c +++ b/auth/credentials/credentials.c @@ -496,24 +496,27 @@ _PUBLIC_ bool cli_credentials_set_old_password(struct cli_credentials *cred, _PUBLIC_ struct samr_Password *cli_credentials_get_nt_hash(struct cli_credentials *cred, TALLOC_CTX *mem_ctx) { - const char *password = cli_credentials_get_password(cred); + const char *password = NULL; - if (password) { + if (cred->nt_hash != NULL) { struct samr_Password *nt_hash = talloc(mem_ctx, struct samr_Password); if (!nt_hash) { return NULL; } - E_md4hash(password, nt_hash->hash); + *nt_hash = *cred->nt_hash; return nt_hash; - } else if (cred->nt_hash != NULL) { + } + + password = cli_credentials_get_password(cred); + if (password) { struct samr_Password *nt_hash = talloc(mem_ctx, struct samr_Password); if (!nt_hash) { return NULL; } - *nt_hash = *cred->nt_hash; + E_md4hash(password, nt_hash->hash); return nt_hash; } diff --git a/auth/credentials/credentials.h b/auth/credentials/credentials.h index 2da47d2cac3..814f01648b0 100644 --- a/auth/credentials/credentials.h +++ b/auth/credentials/credentials.h @@ -191,6 +191,9 @@ enum netr_SchannelType cli_credentials_get_secure_channel_type(struct cli_creden time_t cli_credentials_get_password_last_changed_time(struct cli_credentials *cred); void cli_credentials_set_kvno(struct cli_credentials *cred, int kvno); +bool cli_credentials_set_utf16_password(struct cli_credentials *cred, + const DATA_BLOB *password_utf16, + enum credentials_obtained obtained); bool cli_credentials_set_nt_hash(struct cli_credentials *cred, const struct samr_Password *nt_hash, enum credentials_obtained obtained); diff --git a/auth/credentials/credentials_ntlm.c b/auth/credentials/credentials_ntlm.c index 8c6be395226..5e9aeeda954 100644 --- a/auth/credentials/credentials_ntlm.c +++ b/auth/credentials/credentials_ntlm.c @@ -214,7 +214,60 @@ _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred } return NT_STATUS_OK; } - + +/* + * Set a utf16 password on the credentials context, including an indication + * of 'how' the password was obtained + * + * This is required because the nt_hash is calculated over the raw utf16 blob, + * which might not be completely valid utf16, which means the conversion + * from CH_UTF16MUNGED to CH_UTF8 might loose information. + */ +_PUBLIC_ bool cli_credentials_set_utf16_password(struct cli_credentials *cred, + const DATA_BLOB *password_utf16, + enum credentials_obtained obtained) +{ + if (password_utf16 == NULL) { + return cli_credentials_set_password(cred, NULL, obtained); + } + + if (obtained >= cred->password_obtained) { + struct samr_Password *nt_hash = NULL; + char *password_talloc = NULL; + size_t password_len = 0; + bool ok; + + nt_hash = talloc(cred, struct samr_Password); + if (nt_hash == NULL) { + return false; + } + + ok = convert_string_talloc(cred, + CH_UTF16MUNGED, CH_UTF8, + password_utf16->data, + password_utf16->length, + (void *)&password_talloc, + &password_len); + if (!ok) { + TALLOC_FREE(nt_hash); + return false; + } + + ok = cli_credentials_set_password(cred, password_talloc, obtained); + TALLOC_FREE(password_talloc); + if (!ok) { + TALLOC_FREE(nt_hash); + return false; + } + + mdfour(nt_hash->hash, password_utf16->data, password_utf16->length); + cred->nt_hash = nt_hash; + return true; + } + + return false; +} + _PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred, const struct samr_Password *nt_hash, enum credentials_obtained obtained)