auth/credentials: add cli_credentials_set_utf16_password()
[obnox/samba/samba-obnox.git] / auth / credentials / credentials_ntlm.c
index 7f4af4f08cd8183b829e5bf6b9f6aefe47e30cf4..5e9aeeda9544d0df263002ae9dadd07873e50426 100644 (file)
@@ -26,6 +26,7 @@
 #include "../lib/crypto/crypto.h"
 #include "libcli/auth/libcli_auth.h"
 #include "auth/credentials/credentials.h"
+#include "auth/credentials/credentials_internal.h"
 
 _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, 
                                           int *flags,
@@ -110,7 +111,7 @@ _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred
                /* LM Key is incompatible... */
                *flags &= ~CLI_CRED_LANMAN_AUTH;
        } else if (*flags & CLI_CRED_NTLM2) {
-               struct MD5Context md5_session_nonce_ctx;
+               MD5_CTX md5_session_nonce_ctx;
                uint8_t session_nonce[16];
                uint8_t session_nonce_hash[16];
                uint8_t user_session_key[16];
@@ -174,8 +175,7 @@ _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred
                                        lm_response = nt_response;
                                        /* LM Key is incompatible with 'long' passwords */
                                        *flags &= ~CLI_CRED_LANMAN_AUTH;
-                               } else {
-                                       E_deshash(password, lm_hash);
+                               } else if (E_deshash(password, lm_hash)) {
                                        lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
                                        memcpy(lm_session_key.data, lm_hash, 8);
                                        memset(&lm_session_key.data[8], '\0', 8);
@@ -193,8 +193,7 @@ _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred
                        *flags &= ~CLI_CRED_LANMAN_AUTH;
 
                        password = cli_credentials_get_password(cred);
-                       if (password) {
-                               E_deshash(password, lm_hash);
+                       if (password && E_deshash(password, lm_hash)) {
                                lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
                                memcpy(lm_session_key.data, lm_hash, 8);
                                memset(&lm_session_key.data[8], '\0', 8);
@@ -215,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)