auth/credentials: add cli_credentials_set_utf16_password()
authorStefan Metzmacher <metze@samba.org>
Tue, 16 Dec 2014 13:58:11 +0000 (13:58 +0000)
committerStefan Metzmacher <metze@samba.org>
Fri, 19 Dec 2014 12:15:13 +0000 (13:15 +0100)
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 <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
auth/credentials/credentials.c
auth/credentials/credentials.h
auth/credentials/credentials_ntlm.c

index 78b59556eae953b2f92ee1d687dbb750bf474ebe..a9e4fc864d46426de0d769fa0e5926fdd216bad6 100644 (file)
@@ -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;
        }
index 2da47d2cac3ba766098a97da36f309f5a2bbadad..814f01648b0decb0b59b7294f9e62a96bb55a959 100644 (file)
@@ -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);
index 8c6be39522690e7f6e2c6781b47a165c8c443fe6..5e9aeeda9544d0df263002ae9dadd07873e50426 100644 (file)
@@ -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)