summaryrefslogtreecommitdiff
path: root/auth/credentials
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2016-12-14 10:02:10 +0100
committerAndrew Bartlett <abartlet@samba.org>2016-12-20 01:11:23 +0100
commit1565469bf22cb8aee7467ab76ba64fb5c54b59fe (patch)
tree5afa482723643d78ed139b534dd025506094046a /auth/credentials
parenta3f03df706f3dc8d7875226aa162154a0194f331 (diff)
downloadsamba-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.c107
-rw-r--r--auth/credentials/credentials.h2
-rw-r--r--auth/credentials/credentials_internal.h2
-rw-r--r--auth/credentials/credentials_ntlm.c19
-rw-r--r--auth/credentials/pycredentials.c20
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,