diff options
author | Stefan Metzmacher <metze@samba.org> | 2016-12-14 10:02:10 +0100 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2016-12-20 01:11:23 +0100 |
commit | 1565469bf22cb8aee7467ab76ba64fb5c54b59fe (patch) | |
tree | 5afa482723643d78ed139b534dd025506094046a /auth/credentials | |
parent | a3f03df706f3dc8d7875226aa162154a0194f331 (diff) | |
download | samba-1565469bf22cb8aee7467ab76ba64fb5c54b59fe.tar.gz |
auth/credentials: add cli_credentials_set_password_will_be_nt_hash() and the related logic
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Diffstat (limited to 'auth/credentials')
-rw-r--r-- | auth/credentials/credentials.c | 107 | ||||
-rw-r--r-- | auth/credentials/credentials.h | 2 | ||||
-rw-r--r-- | auth/credentials/credentials_internal.h | 2 | ||||
-rw-r--r-- | auth/credentials/credentials_ntlm.c | 19 | ||||
-rw-r--r-- | auth/credentials/pycredentials.c | 20 |
5 files changed, 135 insertions, 15 deletions
diff --git a/auth/credentials/credentials.c b/auth/credentials/credentials.c index 17f4b5db6a6..e0244287ad5 100644 --- a/auth/credentials/credentials.c +++ b/auth/credentials/credentials.c @@ -318,7 +318,8 @@ _PUBLIC_ const char *cli_credentials_get_password(struct cli_credentials *cred) } if (cred->password_obtained == CRED_CALLBACK && - !cred->callback_running) { + !cred->callback_running && + !cred->password_will_be_nt_hash) { cred->callback_running = true; cred->password = cred->password_cb(cred); cred->callback_running = false; @@ -354,6 +355,29 @@ _PUBLIC_ bool cli_credentials_set_password(struct cli_credentials *cred, return true; } + if (cred->password_will_be_nt_hash) { + struct samr_Password *nt_hash = NULL; + size_t val_len = strlen(val); + size_t converted; + + nt_hash = talloc(cred, struct samr_Password); + if (nt_hash == NULL) { + return false; + } + + converted = strhex_to_str((char *)nt_hash->hash, + sizeof(nt_hash->hash), + val, val_len); + if (converted != sizeof(nt_hash->hash)) { + TALLOC_FREE(nt_hash); + return false; + } + + cred->nt_hash = nt_hash; + cred->password_obtained = obtained; + return true; + } + cred->password = talloc_strdup(cred, val); if (cred->password == NULL) { return false; @@ -424,32 +448,85 @@ _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) { + enum credentials_obtained password_obtained; + enum credentials_obtained ccache_threshold; + enum credentials_obtained client_gss_creds_threshold; + bool password_is_nt_hash; const char *password = NULL; + struct samr_Password *nt_hash = NULL; if (cred->nt_hash != NULL) { - struct samr_Password *nt_hash = talloc(mem_ctx, struct samr_Password); - if (!nt_hash) { - return NULL; - } + /* + * If we already have a hash it's easy. + */ + goto return_hash; + } - *nt_hash = *cred->nt_hash; + /* + * This is a bit tricky, with password_will_be_nt_hash + * we still need to get the value via the password_callback + * but if we did that we should not remember it's state + * in the long run so we need to undo it. + */ - return nt_hash; - } + password_obtained = cred->password_obtained; + ccache_threshold = cred->ccache_threshold; + client_gss_creds_threshold = cred->client_gss_creds_threshold; + password_is_nt_hash = cred->password_will_be_nt_hash; + cred->password_will_be_nt_hash = false; password = cli_credentials_get_password(cred); - if (password) { - struct samr_Password *nt_hash = talloc(mem_ctx, struct samr_Password); - if (!nt_hash) { - return NULL; - } + cred->password_will_be_nt_hash = password_is_nt_hash; + if (password_is_nt_hash && password_obtained == CRED_CALLBACK) { + /* + * We got the nt_hash as string via the callback, + * so we need to undo the state change. + * + * And also don't remember it as plaintext password. + */ + cred->client_gss_creds_threshold = client_gss_creds_threshold; + cred->ccache_threshold = ccache_threshold; + cred->password_obtained = password_obtained; + cred->password = NULL; + } + + if (password == NULL) { + return NULL; + } + + nt_hash = talloc(cred, struct samr_Password); + if (nt_hash == NULL) { + return NULL; + } + + if (password_is_nt_hash) { + size_t password_len = strlen(password); + size_t converted; + + converted = strhex_to_str((char *)nt_hash->hash, + sizeof(nt_hash->hash), + password, password_len); + if (converted != sizeof(nt_hash->hash)) { + TALLOC_FREE(nt_hash); + return false; + } + } else { E_md4hash(password, nt_hash->hash); + } - return nt_hash; + cred->nt_hash = nt_hash; + nt_hash = NULL; + +return_hash: + nt_hash = talloc(mem_ctx, struct samr_Password); + if (nt_hash == NULL) { + return NULL; } - return NULL; + *nt_hash = *cred->nt_hash; + + return nt_hash; } /** diff --git a/auth/credentials/credentials.h b/auth/credentials/credentials.h index 523793f090d..6b0d83bb5d4 100644 --- a/auth/credentials/credentials.h +++ b/auth/credentials/credentials.h @@ -201,6 +201,8 @@ bool cli_credentials_set_utf16_password(struct cli_credentials *cred, enum credentials_obtained obtained); bool cli_credentials_set_old_utf16_password(struct cli_credentials *cred, const DATA_BLOB *password_utf16); +void cli_credentials_set_password_will_be_nt_hash(struct cli_credentials *cred, + bool val); 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_internal.h b/auth/credentials/credentials_internal.h index f88ae707070..68f1f25dce1 100644 --- a/auth/credentials/credentials_internal.h +++ b/auth/credentials/credentials_internal.h @@ -115,6 +115,8 @@ struct cli_credentials { bool callback_running; char winbind_separator; + + bool password_will_be_nt_hash; }; #endif /* __CREDENTIALS_INTERNAL_H__ */ diff --git a/auth/credentials/credentials_ntlm.c b/auth/credentials/credentials_ntlm.c index 2a4c1413501..e6859bf9c45 100644 --- a/auth/credentials/credentials_ntlm.c +++ b/auth/credentials/credentials_ntlm.c @@ -301,6 +301,8 @@ _PUBLIC_ bool cli_credentials_set_utf16_password(struct cli_credentials *cred, const DATA_BLOB *password_utf16, enum credentials_obtained obtained) { + cred->password_will_be_nt_hash = false; + if (password_utf16 == NULL) { return cli_credentials_set_password(cred, NULL, obtained); } @@ -389,10 +391,27 @@ _PUBLIC_ bool cli_credentials_set_old_utf16_password(struct cli_credentials *cre return true; } +_PUBLIC_ void cli_credentials_set_password_will_be_nt_hash(struct cli_credentials *cred, + bool val) +{ + /* + * We set this here and the next cli_credentials_set_password() + * that resets the password or password callback + * will pick this up. + * + * cli_credentials_set_nt_hash() and + * cli_credentials_set_utf16_password() will reset this + * to false. + */ + cred->password_will_be_nt_hash = val; +} + _PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred, const struct samr_Password *nt_hash, enum credentials_obtained obtained) { + cred->password_will_be_nt_hash = false; + if (obtained >= cred->password_obtained) { cli_credentials_set_password(cred, NULL, obtained); if (nt_hash) { diff --git a/auth/credentials/pycredentials.c b/auth/credentials/pycredentials.c index 9ea06823851..e0b73922446 100644 --- a/auth/credentials/pycredentials.c +++ b/auth/credentials/pycredentials.c @@ -299,6 +299,21 @@ static PyObject *py_creds_parse_string(PyObject *self, PyObject *args) Py_RETURN_NONE; } +static PyObject *py_cli_credentials_set_password_will_be_nt_hash(PyObject *self, PyObject *args) +{ + struct cli_credentials *creds = PyCredentials_AsCliCredentials(self); + PyObject *py_val = NULL; + bool val = false; + + if (!PyArg_ParseTuple(args, "O!", &PyBool_Type, &py_val)) { + return NULL; + } + val = PyObject_IsTrue(py_val); + + cli_credentials_set_password_will_be_nt_hash(creds, val); + Py_RETURN_NONE; +} + static PyObject *py_creds_get_nt_hash(PyObject *self, PyObject *unused) { PyObject *ret; @@ -564,6 +579,11 @@ static PyMethodDef py_creds_methods[] = { { "parse_string", py_creds_parse_string, METH_VARARGS, "S.parse_string(text, obtained=CRED_SPECIFIED) -> None\n" "Parse credentials string." }, + { "set_password_will_be_nt_hash", + py_cli_credentials_set_password_will_be_nt_hash, METH_VARARGS, + "S.set_password_will_be_nt_hash(bool) -> None\n" + "Alters the behaviour of S.set_password() " + "to expect the NTHASH as hexstring." }, { "get_nt_hash", py_creds_get_nt_hash, METH_NOARGS, NULL }, { "get_kerberos_state", py_creds_get_kerberos_state, METH_NOARGS, |