[Patches] auth/credentials for user_auth_info
Stefan Metzmacher
metze at samba.org
Fri Dec 16 21:58:32 UTC 2016
Hi,
here're some patches to prepare the auth/credentials logic for
usage within struct user_auth_info.
This took quite some cycles to pass a full autobuild, it turns
out that we have a lot of explicit and implicit test cavarage
of the source3 POPT_COMMON_CREDENTIALS handling.
Please review and push:-)
This depends on the "Avoid selftest/autobuild interaction with /tmp"
patchset.
Thanks!
metze
-------------- next part --------------
From e579c1ad506cf9cb308f230974aba6da20381d28 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 14 Dec 2016 08:50:51 +0100
Subject: [PATCH 01/19] auth/credentials: make use of talloc_zero() in
cli_credentials_init()
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
auth/credentials/credentials.c | 76 +-----------------------------------------
1 file changed, 1 insertion(+), 75 deletions(-)
diff --git a/auth/credentials/credentials.c b/auth/credentials/credentials.c
index c8f86ba..7f4c15f 100644
--- a/auth/credentials/credentials.c
+++ b/auth/credentials/credentials.c
@@ -36,85 +36,11 @@
*/
_PUBLIC_ struct cli_credentials *cli_credentials_init(TALLOC_CTX *mem_ctx)
{
- struct cli_credentials *cred = talloc(mem_ctx, struct cli_credentials);
+ struct cli_credentials *cred = talloc_zero(mem_ctx, struct cli_credentials);
if (cred == NULL) {
return cred;
}
- cred->workstation_obtained = CRED_UNINITIALISED;
- cred->username_obtained = CRED_UNINITIALISED;
- cred->password_obtained = CRED_UNINITIALISED;
- cred->domain_obtained = CRED_UNINITIALISED;
- cred->realm_obtained = CRED_UNINITIALISED;
- cred->ccache_obtained = CRED_UNINITIALISED;
- cred->client_gss_creds_obtained = CRED_UNINITIALISED;
- cred->principal_obtained = CRED_UNINITIALISED;
- cred->keytab_obtained = CRED_UNINITIALISED;
- cred->server_gss_creds_obtained = CRED_UNINITIALISED;
-
- cred->ccache_threshold = CRED_UNINITIALISED;
- cred->client_gss_creds_threshold = CRED_UNINITIALISED;
-
- cred->workstation = NULL;
- cred->username = NULL;
- cred->password = NULL;
- cred->old_password = NULL;
- cred->domain = NULL;
- cred->realm = NULL;
- cred->principal = NULL;
- cred->salt_principal = NULL;
- cred->impersonate_principal = NULL;
- cred->self_service = NULL;
- cred->target_service = NULL;
-
- cred->bind_dn = NULL;
-
- cred->nt_hash = NULL;
- cred->old_nt_hash = NULL;
-
- cred->lm_response.data = NULL;
- cred->lm_response.length = 0;
- cred->nt_response.data = NULL;
- cred->nt_response.length = 0;
-
- cred->ccache = NULL;
- cred->client_gss_creds = NULL;
- cred->keytab = NULL;
- cred->server_gss_creds = NULL;
-
- cred->workstation_cb = NULL;
- cred->password_cb = NULL;
- cred->username_cb = NULL;
- cred->domain_cb = NULL;
- cred->realm_cb = NULL;
- cred->principal_cb = NULL;
-
- cred->priv_data = NULL;
-
- cred->netlogon_creds = NULL;
- cred->secure_channel_type = SEC_CHAN_NULL;
-
- cred->kvno = 0;
-
- cred->password_last_changed_time = 0;
-
- cred->smb_krb5_context = NULL;
-
- cred->machine_account_pending = false;
- cred->machine_account_pending_lp_ctx = NULL;
-
- cred->machine_account = false;
-
- cred->password_tries = 0;
-
- cred->callback_running = false;
-
- cli_credentials_set_kerberos_state(cred, CRED_AUTO_USE_KERBEROS);
- cli_credentials_set_gensec_features(cred, 0);
- cli_credentials_set_krb_forwardable(cred, CRED_AUTO_KRB_FORWARDABLE);
-
- cred->forced_sasl_mech = NULL;
-
cred->winbind_separator = '\\';
return cred;
--
1.9.1
From a6277b007bc75f9a3402d934bfd753343062b3ae Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 14 Dec 2016 08:52:12 +0100
Subject: [PATCH 02/19] auth/credentials: let cli_credentials_set_password()
fail if talloc_strdup() fails
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
auth/credentials/credentials.c | 27 ++++++++++++++++++++-------
1 file changed, 20 insertions(+), 7 deletions(-)
diff --git a/auth/credentials/credentials.c b/auth/credentials/credentials.c
index 7f4c15f..17f4b5d 100644
--- a/auth/credentials/credentials.c
+++ b/auth/credentials/credentials.c
@@ -339,18 +339,31 @@ _PUBLIC_ bool cli_credentials_set_password(struct cli_credentials *cred,
enum credentials_obtained obtained)
{
if (obtained >= cred->password_obtained) {
+
+ cred->lm_response = data_blob_null;
+ cred->nt_response = data_blob_null;
+ cred->nt_hash = NULL;
+ cred->password = NULL;
+
+ cli_credentials_invalidate_ccache(cred, obtained);
+
cred->password_tries = 0;
+
+ if (val == NULL) {
+ cred->password_obtained = obtained;
+ return true;
+ }
+
cred->password = talloc_strdup(cred, val);
- if (cred->password) {
- /* Don't print the actual password in talloc memory dumps */
- talloc_set_name_const(cred->password, "password set via cli_credentials_set_password");
+ if (cred->password == NULL) {
+ return false;
}
+
+ /* Don't print the actual password in talloc memory dumps */
+ talloc_set_name_const(cred->password,
+ "password set via cli_credentials_set_password");
cred->password_obtained = obtained;
- cli_credentials_invalidate_ccache(cred, cred->password_obtained);
- cred->nt_hash = NULL;
- cred->lm_response = data_blob(NULL, 0);
- cred->nt_response = data_blob(NULL, 0);
return true;
}
--
1.9.1
From 5cb3c481ba026873e2893133ca603ff0003cf930 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 14 Dec 2016 10:02:10 +0100
Subject: [PATCH 03/19] auth/credentials: add
cli_credentials_set_password_will_be_nt_hash() and the related logic
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
auth/credentials/credentials.c | 107 +++++++++++++++++++++++++++-----
auth/credentials/credentials.h | 2 +
auth/credentials/credentials_internal.h | 2 +
auth/credentials/credentials_ntlm.c | 19 ++++++
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 17f4b5d..e024428 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 523793f..6b0d83b 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 f88ae70..68f1f25 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 2a4c141..e6859bf 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 9ea0682..e0b7392 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,
--
1.9.1
From 8deffe86ac28dfc28704275e4bbcb14220fbc135 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 15 Dec 2016 09:34:45 +0100
Subject: [PATCH 04/19] tests/credentials.py: add test for
cli_credentials_set_password_will_be_nt_hash()
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
python/samba/tests/credentials.py | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/python/samba/tests/credentials.py b/python/samba/tests/credentials.py
index a228327..c27edd77 100644
--- a/python/samba/tests/credentials.py
+++ b/python/samba/tests/credentials.py
@@ -24,6 +24,7 @@ the functionality, that's already done in other tests.
from samba import credentials
import samba.tests
import os
+import binascii
class CredentialsTests(samba.tests.TestCase):
@@ -95,8 +96,19 @@ class CredentialsTests(samba.tests.TestCase):
self.assertEqual("myworksta", self.creds.get_workstation())
def test_get_nt_hash(self):
- self.creds.set_password("geheim")
- self.assertEqual('\xc2\xae\x1f\xe6\xe6H\x84cRE>\x81o*\xeb\x93',
+ password="geheim"
+ hex_nthash="c2ae1fe6e648846352453e816f2aeb93"
+ self.creds.set_password(password)
+ self.assertEqual(password, self.creds.get_password())
+ self.assertEqual(binascii.a2b_hex(hex_nthash),
+ self.creds.get_nt_hash())
+
+ def test_get_nt_hash_string(self):
+ self.creds.set_password_will_be_nt_hash(True)
+ hex_nthash="c2ae1fe6e648846352453e816f2aeb93"
+ self.creds.set_password(hex_nthash)
+ self.assertEqual(None, self.creds.get_password())
+ self.assertEqual(binascii.a2b_hex(hex_nthash),
self.creds.get_nt_hash())
def test_set_cmdline_callbacks(self):
--
1.9.1
From d18e69a06a5966f2aae0ced4403d39abbbe4d443 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 15 Dec 2016 09:42:20 +0100
Subject: [PATCH 05/19] tests/credentials.py: verify the difference of
parse_string("someone") and parse_string("someone%")
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
python/samba/tests/credentials.py | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/python/samba/tests/credentials.py b/python/samba/tests/credentials.py
index c27edd77..ad3f663 100644
--- a/python/samba/tests/credentials.py
+++ b/python/samba/tests/credentials.py
@@ -70,6 +70,16 @@ class CredentialsTests(samba.tests.TestCase):
self.assertEqual("", self.creds.get_username())
self.assertEqual(None, self.creds.get_password())
+ def test_parse_string_empty_pw(self):
+ self.creds.parse_string("someone%")
+ self.assertEqual("someone", self.creds.get_username())
+ self.assertEqual("", self.creds.get_password())
+
+ def test_parse_string_none_pw(self):
+ self.creds.parse_string("someone")
+ self.assertEqual("someone", self.creds.get_username())
+ self.assertEqual(None, self.creds.get_password())
+
def test_parse_string_user_pw_domain(self):
self.creds.parse_string("dom\\someone%secr")
self.assertEqual("someone", self.creds.get_username())
--
1.9.1
From 605e3a23a8261cf13f9f1caffc0a85ae0c8eb0cb Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 15 Dec 2016 10:06:25 +0100
Subject: [PATCH 06/19] auth/credentials: add py_creds_parse_file()
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
auth/credentials/pycredentials.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/auth/credentials/pycredentials.c b/auth/credentials/pycredentials.c
index e0b7392..d38d0e3 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_creds_parse_file(PyObject *self, PyObject *args)
+{
+ char *newval;
+ enum credentials_obtained obt = CRED_SPECIFIED;
+ int _obt = obt;
+
+ if (!PyArg_ParseTuple(args, "s|i", &newval, &_obt)) {
+ return NULL;
+ }
+ obt = _obt;
+
+ cli_credentials_parse_file(PyCredentials_AsCliCredentials(self), newval, obt);
+ 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);
@@ -579,6 +594,9 @@ 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." },
+ { "parse_file", py_creds_parse_file, METH_VARARGS,
+ "S.parse_file(filename, obtained=CRED_SPECIFIED) -> None\n"
+ "Parse credentials file." },
{ "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"
--
1.9.1
From 4b268fadf90275104950e2d60aea9c18e8f0c297 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 15 Dec 2016 10:30:29 +0100
Subject: [PATCH 07/19] tests/credentials.py: add very simple test for
py_creds_parse_file
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
python/samba/tests/credentials.py | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/python/samba/tests/credentials.py b/python/samba/tests/credentials.py
index ad3f663..0a64179d 100644
--- a/python/samba/tests/credentials.py
+++ b/python/samba/tests/credentials.py
@@ -26,7 +26,7 @@ import samba.tests
import os
import binascii
-class CredentialsTests(samba.tests.TestCase):
+class CredentialsTests(samba.tests.TestCaseInTempDir):
def setUp(self):
super(CredentialsTests, self).setUp()
@@ -156,6 +156,28 @@ class CredentialsTests(samba.tests.TestCase):
self.assertEqual(creds.is_anonymous(), True)
self.assertEqual(creds.authentication_requested(), False)
+ def test_parse_file_1(self):
+ realm="realm.example.com"
+ domain="dom"
+ password="pass"
+ username="user"
+
+ passwd_file_name = os.path.join(self.tempdir, "parse_file")
+ passwd_file_fd = open(passwd_file_name, 'wx')
+ passwd_file_fd.write("realm=%s\n" % realm)
+ passwd_file_fd.write("domain=%s\n" % domain)
+ passwd_file_fd.write("username=%s\n" % username)
+ passwd_file_fd.write("password=%s\n" % password)
+ passwd_file_fd.close()
+ self.creds.parse_file(passwd_file_name)
+ self.assertEqual(self.creds.get_username(), username)
+ self.assertEqual(self.creds.get_password(), password)
+ self.assertEqual(self.creds.get_domain(), domain.upper())
+ self.assertEqual(self.creds.get_realm(), realm.upper())
+ self.assertEqual(self.creds.is_anonymous(), False)
+ self.assertEqual(self.creds.authentication_requested(), True)
+ os.unlink(passwd_file_name)
+
def test_parse_username(self):
creds = credentials.Credentials()
lp = samba.tests.env_loadparm()
--
1.9.1
From 2fb70a73e7098f807b79ebe002780b46c685defd Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 15 Dec 2016 11:37:33 +0100
Subject: [PATCH 08/19] auth/credentials: add python bindings for enum
credentials_obtained
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
auth/credentials/pycredentials.c | 27 +++++++++++++++++----------
1 file changed, 17 insertions(+), 10 deletions(-)
diff --git a/auth/credentials/pycredentials.c b/auth/credentials/pycredentials.c
index d38d0e3..6da64a6 100644
--- a/auth/credentials/pycredentials.c
+++ b/auth/credentials/pycredentials.c
@@ -528,12 +528,12 @@ static PyMethodDef py_creds_methods[] = {
{ "get_username", py_creds_get_username, METH_NOARGS,
"S.get_username() -> username\nObtain username." },
{ "set_username", py_creds_set_username, METH_VARARGS,
- "S.set_username(name, obtained=CRED_SPECIFIED) -> None\n"
+ "S.set_username(name[, credentials.SPECIFIED]) -> None\n"
"Change username." },
{ "get_principal", py_creds_get_principal, METH_NOARGS,
"S.get_principal() -> user at realm\nObtain user principal." },
{ "set_principal", py_creds_set_principal, METH_VARARGS,
- "S.set_principal(name, obtained=CRED_SPECIFIED) -> None\n"
+ "S.set_principal(name[, credentials.SPECIFIED]) -> None\n"
"Change principal." },
{ "get_password", py_creds_get_password, METH_NOARGS,
"S.get_password() -> password\n"
@@ -542,31 +542,31 @@ static PyMethodDef py_creds_methods[] = {
"S.get_ntlm_username_domain() -> (domain, username)\n"
"Obtain NTLM username and domain, split up either as (DOMAIN, user) or (\"\", \"user at realm\")." },
{ "set_password", py_creds_set_password, METH_VARARGS,
- "S.set_password(password, obtained=CRED_SPECIFIED) -> None\n"
+ "S.set_password(password[, credentials.SPECIFIED]) -> None\n"
"Change password." },
{ "set_utf16_password", py_creds_set_utf16_password, METH_VARARGS,
- "S.set_utf16_password(password, obtained=CRED_SPECIFIED) -> None\n"
+ "S.set_utf16_password(password[, credentials.SPECIFIED]) -> None\n"
"Change password." },
{ "get_old_password", py_creds_get_old_password, METH_NOARGS,
"S.get_old_password() -> password\n"
"Obtain old password." },
{ "set_old_password", py_creds_set_old_password, METH_VARARGS,
- "S.set_old_password(password, obtained=CRED_SPECIFIED) -> None\n"
+ "S.set_old_password(password[, credentials.SPECIFIED]) -> None\n"
"Change old password." },
{ "set_old_utf16_password", py_creds_set_old_utf16_password, METH_VARARGS,
- "S.set_old_utf16_password(password, obtained=CRED_SPECIFIED) -> None\n"
+ "S.set_old_utf16_password(password[, credentials.SPECIFIED]) -> None\n"
"Change old password." },
{ "get_domain", py_creds_get_domain, METH_NOARGS,
"S.get_domain() -> domain\n"
"Obtain domain name." },
{ "set_domain", py_creds_set_domain, METH_VARARGS,
- "S.set_domain(domain, obtained=CRED_SPECIFIED) -> None\n"
+ "S.set_domain(domain[, credentials.SPECIFIED]) -> None\n"
"Change domain name." },
{ "get_realm", py_creds_get_realm, METH_NOARGS,
"S.get_realm() -> realm\n"
"Obtain realm name." },
{ "set_realm", py_creds_set_realm, METH_VARARGS,
- "S.set_realm(realm, obtained=CRED_SPECIFIED) -> None\n"
+ "S.set_realm(realm[, credentials.SPECIFIED]) -> None\n"
"Change realm name." },
{ "get_bind_dn", py_creds_get_bind_dn, METH_NOARGS,
"S.get_bind_dn() -> bind dn\n"
@@ -592,10 +592,10 @@ static PyMethodDef py_creds_methods[] = {
"S.set_cmdline_callbacks() -> bool\n"
"Use command-line to obtain credentials not explicitly set." },
{ "parse_string", py_creds_parse_string, METH_VARARGS,
- "S.parse_string(text, obtained=CRED_SPECIFIED) -> None\n"
+ "S.parse_string(text[, credentials.SPECIFIED]) -> None\n"
"Parse credentials string." },
{ "parse_file", py_creds_parse_file, METH_VARARGS,
- "S.parse_file(filename, obtained=CRED_SPECIFIED) -> None\n"
+ "S.parse_file(filename[, credentials.SPECIFIED]) -> None\n"
"Parse credentials file." },
{ "set_password_will_be_nt_hash",
py_cli_credentials_set_password_will_be_nt_hash, METH_VARARGS,
@@ -649,6 +649,13 @@ void initcredentials(void)
if (m == NULL)
return;
+ PyModule_AddObject(m, "UNINITIALISED", PyInt_FromLong(CRED_UNINITIALISED));
+ PyModule_AddObject(m, "CALLBACK", PyInt_FromLong(CRED_CALLBACK));
+ PyModule_AddObject(m, "GUESS_ENV", PyInt_FromLong(CRED_GUESS_ENV));
+ PyModule_AddObject(m, "GUESS_FILE", PyInt_FromLong(CRED_GUESS_FILE));
+ PyModule_AddObject(m, "CALLBACK_RESULT", PyInt_FromLong(CRED_CALLBACK_RESULT));
+ PyModule_AddObject(m, "SPECIFIED", PyInt_FromLong(CRED_SPECIFIED));
+
PyModule_AddObject(m, "AUTO_USE_KERBEROS", PyInt_FromLong(CRED_AUTO_USE_KERBEROS));
PyModule_AddObject(m, "DONT_USE_KERBEROS", PyInt_FromLong(CRED_DONT_USE_KERBEROS));
PyModule_AddObject(m, "MUST_USE_KERBEROS", PyInt_FromLong(CRED_MUST_USE_KERBEROS));
--
1.9.1
From f6abd98d87c9df95c1eab1fb5ad91f1182157c2d Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 15 Dec 2016 11:04:02 +0100
Subject: [PATCH 09/19] auth/credentials: handle situations without a
configured (default) realm
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
auth/credentials/credentials.c | 43 +++++++++++++++++++++++++++++++--------
python/samba/tests/credentials.py | 19 ++++++++++++-----
2 files changed, 48 insertions(+), 14 deletions(-)
diff --git a/auth/credentials/credentials.c b/auth/credentials/credentials.c
index e024428..a0f91e9 100644
--- a/auth/credentials/credentials.c
+++ b/auth/credentials/credentials.c
@@ -213,16 +213,37 @@ _PUBLIC_ const char *cli_credentials_get_principal_and_obtained(struct cli_crede
if (cred->principal_obtained < cred->username_obtained
|| cred->principal_obtained < MAX(cred->domain_obtained, cred->realm_obtained)) {
+ const char *effective_username = NULL;
+ const char *effective_realm = NULL;
+ enum credentials_obtained effective_obtained;
+
+ effective_username = cli_credentials_get_username(cred);
+ if (effective_username == NULL || strlen(effective_username) == 0) {
+ *obtained = cred->username_obtained;
+ return NULL;
+ }
+
if (cred->domain_obtained > cred->realm_obtained) {
- *obtained = MIN(cred->domain_obtained, cred->username_obtained);
- return talloc_asprintf(mem_ctx, "%s@%s",
- cli_credentials_get_username(cred),
- cli_credentials_get_domain(cred));
+ effective_realm = cli_credentials_get_domain(cred);
+ effective_obtained = MIN(cred->domain_obtained,
+ cred->username_obtained);
} else {
- *obtained = MIN(cred->realm_obtained, cred->username_obtained);
+ effective_realm = cli_credentials_get_realm(cred);
+ effective_obtained = MIN(cred->realm_obtained,
+ cred->username_obtained);
+ }
+
+ if (effective_realm == NULL || strlen(effective_realm) == 0) {
+ effective_realm = cli_credentials_get_domain(cred);
+ effective_obtained = MIN(cred->domain_obtained,
+ cred->username_obtained);
+ }
+
+ if (effective_realm != NULL && strlen(effective_realm) != 0) {
+ *obtained = effective_obtained;
return talloc_asprintf(mem_ctx, "%s@%s",
- cli_credentials_get_username(cred),
- cli_credentials_get_realm(cred));
+ effective_username,
+ effective_realm);
}
}
*obtained = cred->principal_obtained;
@@ -816,6 +837,7 @@ _PUBLIC_ void cli_credentials_set_conf(struct cli_credentials *cred,
struct loadparm_context *lp_ctx)
{
const char *sep = NULL;
+ const char *realm = lpcfg_realm(lp_ctx);
cli_credentials_set_username(cred, "", CRED_UNINITIALISED);
if (lpcfg_parm_is_cmdline(lp_ctx, "workgroup")) {
@@ -828,10 +850,13 @@ _PUBLIC_ void cli_credentials_set_conf(struct cli_credentials *cred,
} else {
cli_credentials_set_workstation(cred, lpcfg_netbios_name(lp_ctx), CRED_UNINITIALISED);
}
+ if (realm != NULL && strlen(realm) == 0) {
+ realm = NULL;
+ }
if (lpcfg_parm_is_cmdline(lp_ctx, "realm")) {
- cli_credentials_set_realm(cred, lpcfg_realm(lp_ctx), CRED_SPECIFIED);
+ cli_credentials_set_realm(cred, realm, CRED_SPECIFIED);
} else {
- cli_credentials_set_realm(cred, lpcfg_realm(lp_ctx), CRED_UNINITIALISED);
+ cli_credentials_set_realm(cred, realm, CRED_UNINITIALISED);
}
sep = lpcfg_winbind_separator(lp_ctx);
diff --git a/python/samba/tests/credentials.py b/python/samba/tests/credentials.py
index 0a64179d..1cbd540 100644
--- a/python/samba/tests/credentials.py
+++ b/python/samba/tests/credentials.py
@@ -60,10 +60,12 @@ class CredentialsTests(samba.tests.TestCaseInTempDir):
def test_set_domain(self):
self.creds.set_domain("ABMAS")
self.assertEqual("ABMAS", self.creds.get_domain())
+ self.assertEqual(self.creds.get_principal(), None)
def test_set_realm(self):
self.creds.set_realm("myrealm")
self.assertEqual("MYREALM", self.creds.get_realm())
+ self.assertEqual(self.creds.get_principal(), None)
def test_parse_string_anon(self):
self.creds.parse_string("%")
@@ -140,7 +142,8 @@ class CredentialsTests(samba.tests.TestCaseInTempDir):
creds.guess(lp)
self.assertEqual(creds.get_username(), "env_user")
self.assertEqual(creds.get_domain(), lp.get("workgroup").upper())
- self.assertEqual(creds.get_realm(), lp.get("realm").upper())
+ self.assertEqual(creds.get_realm(), None)
+ self.assertEqual(creds.get_principal(), "env_user@%s" % creds.get_domain())
self.assertEqual(creds.is_anonymous(), False)
self.assertEqual(creds.authentication_requested(), False)
@@ -153,6 +156,7 @@ class CredentialsTests(samba.tests.TestCaseInTempDir):
self.assertEqual(creds.get_username(), "")
self.assertEqual(creds.get_domain(), "")
self.assertEqual(creds.get_realm(), None)
+ self.assertEqual(creds.get_principal(), None)
self.assertEqual(creds.is_anonymous(), True)
self.assertEqual(creds.authentication_requested(), False)
@@ -186,7 +190,8 @@ class CredentialsTests(samba.tests.TestCaseInTempDir):
creds.parse_string("user")
self.assertEqual(creds.get_username(), "user")
self.assertEqual(creds.get_domain(), lp.get("workgroup").upper())
- self.assertEqual(creds.get_realm(), lp.get("realm").upper())
+ self.assertEqual(creds.get_realm(), None)
+ self.assertEqual(creds.get_principal(), "user@%s" % lp.get("workgroup").upper())
self.assertEqual(creds.is_anonymous(), False)
self.assertEqual(creds.authentication_requested(), True)
@@ -198,7 +203,8 @@ class CredentialsTests(samba.tests.TestCaseInTempDir):
creds.parse_string("domain\user")
self.assertEqual(creds.get_username(), "user")
self.assertEqual(creds.get_domain(), "DOMAIN")
- self.assertEqual(creds.get_realm(), lp.get("realm").upper())
+ self.assertEqual(creds.get_realm(), None)
+ self.assertEqual(creds.get_principal(), "user at DOMAIN")
self.assertEqual(creds.is_anonymous(), False)
self.assertEqual(creds.authentication_requested(), True)
@@ -211,6 +217,7 @@ class CredentialsTests(samba.tests.TestCaseInTempDir):
self.assertEqual(creds.get_username(), "env_user")
self.assertEqual(creds.get_domain(), lp.get("workgroup").upper())
self.assertEqual(creds.get_realm(), "SAMBA.ORG")
+ self.assertEqual(creds.get_principal(), "user at samba.org")
self.assertEqual(creds.is_anonymous(), False)
self.assertEqual(creds.authentication_requested(), True)
@@ -223,7 +230,8 @@ class CredentialsTests(samba.tests.TestCaseInTempDir):
self.assertEqual(creds.get_username(), "user")
self.assertEqual(creds.get_password(), "pass")
self.assertEqual(creds.get_domain(), lp.get("workgroup"))
- self.assertEqual(creds.get_realm(), lp.get("realm"))
+ self.assertEqual(creds.get_realm(), None)
+ self.assertEqual(creds.get_principal(), "user@%s" % lp.get("workgroup"))
self.assertEqual(creds.is_anonymous(), False)
self.assertEqual(creds.authentication_requested(), True)
@@ -236,7 +244,8 @@ class CredentialsTests(samba.tests.TestCaseInTempDir):
self.assertEqual(creds.get_username(), "user")
self.assertEqual(creds.get_domain(), "DOMAIN")
self.assertEqual(creds.get_password(), "pass")
- self.assertEqual(creds.get_realm(), lp.get("realm"))
+ self.assertEqual(creds.get_realm(), None)
+ self.assertEqual(creds.get_principal(), "user at DOMAIN")
self.assertEqual(creds.is_anonymous(), False)
self.assertEqual(creds.authentication_requested(), True)
--
1.9.1
From 297f8e1e363c7ae8496fa7014fd841371f4c5efc Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 15 Dec 2016 14:49:18 +0100
Subject: [PATCH 10/19] tests/credentials.py: add tests with a realm from
smb.conf
As we don't want to create a new smb.conf file
we just simulate it with "creds.set_realm(realm, credentials.UNINITIALISED)".
That's basically the same as the cli_credentials_set_conf() behaviour
if a realm is specified in the configuration.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
python/samba/tests/credentials.py | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/python/samba/tests/credentials.py b/python/samba/tests/credentials.py
index 1cbd540..8bfab7a 100644
--- a/python/samba/tests/credentials.py
+++ b/python/samba/tests/credentials.py
@@ -182,7 +182,7 @@ class CredentialsTests(samba.tests.TestCaseInTempDir):
self.assertEqual(self.creds.authentication_requested(), True)
os.unlink(passwd_file_name)
- def test_parse_username(self):
+ def test_parse_username_0(self):
creds = credentials.Credentials()
lp = samba.tests.env_loadparm()
os.environ["USER"] = "env_user"
@@ -195,6 +195,21 @@ class CredentialsTests(samba.tests.TestCaseInTempDir):
self.assertEqual(creds.is_anonymous(), False)
self.assertEqual(creds.authentication_requested(), True)
+ def test_parse_username_1(self):
+ creds = credentials.Credentials()
+ lp = samba.tests.env_loadparm()
+ os.environ["USER"] = "env_user"
+ creds.guess(lp)
+ realm = "realm.example.com"
+ creds.set_realm(realm, credentials.UNINITIALISED)
+ creds.parse_string("user")
+ self.assertEqual(creds.get_username(), "user")
+ self.assertEqual(creds.get_domain(), lp.get("workgroup").upper())
+ self.assertEqual(creds.get_realm(), realm.upper())
+ self.assertEqual(creds.get_principal(), "user@%s" % realm.upper())
+ self.assertEqual(creds.is_anonymous(), False)
+ self.assertEqual(creds.authentication_requested(), True)
+
def test_parse_username_with_domain(self):
creds = credentials.Credentials()
lp = samba.tests.env_loadparm()
--
1.9.1
From d6fd84cc91b85e1eb34e1a7cb0183d18b93223dd Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 9 Dec 2016 12:20:19 +0100
Subject: [PATCH 11/19] auth/credentials: let cli_credentials_parse_string()
always reset username and domain
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
auth/credentials/credentials.c | 8 ++++++++
python/samba/tests/credentials.py | 8 ++++----
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/auth/credentials/credentials.c b/auth/credentials/credentials.c
index a0f91e9..cca772d 100644
--- a/auth/credentials/credentials.c
+++ b/auth/credentials/credentials.c
@@ -781,6 +781,14 @@ _PUBLIC_ void cli_credentials_parse_string(struct cli_credentials *credentials,
}
if ((p = strchr_m(uname,'@'))) {
+ /*
+ * We also need to set username and domain
+ * in order to undo the effect of
+ * cli_credentials_guess().
+ */
+ cli_credentials_set_username(credentials, uname, obtained);
+ cli_credentials_set_domain(credentials, "", obtained);
+
cli_credentials_set_principal(credentials, uname, obtained);
*p = 0;
cli_credentials_set_realm(credentials, p+1, obtained);
diff --git a/python/samba/tests/credentials.py b/python/samba/tests/credentials.py
index 8bfab7a..82a8ad9 100644
--- a/python/samba/tests/credentials.py
+++ b/python/samba/tests/credentials.py
@@ -229,8 +229,8 @@ class CredentialsTests(samba.tests.TestCaseInTempDir):
os.environ["USER"] = "env_user"
creds.guess(lp)
creds.parse_string("user at samba.org")
- self.assertEqual(creds.get_username(), "env_user")
- self.assertEqual(creds.get_domain(), lp.get("workgroup").upper())
+ self.assertEqual(creds.get_username(), "user at samba.org")
+ self.assertEqual(creds.get_domain(), "")
self.assertEqual(creds.get_realm(), "SAMBA.ORG")
self.assertEqual(creds.get_principal(), "user at samba.org")
self.assertEqual(creds.is_anonymous(), False)
@@ -270,8 +270,8 @@ class CredentialsTests(samba.tests.TestCaseInTempDir):
os.environ["USER"] = "env_user"
creds.guess(lp)
creds.parse_string("user at samba.org%pass")
- self.assertEqual(creds.get_username(), "env_user")
- self.assertEqual(creds.get_domain(), lp.get("workgroup").upper())
+ self.assertEqual(creds.get_username(), "user at samba.org")
+ self.assertEqual(creds.get_domain(), "")
self.assertEqual(creds.get_password(), "pass")
self.assertEqual(creds.get_realm(), "SAMBA.ORG")
self.assertEqual(creds.get_principal(), "user at samba.org")
--
1.9.1
From c1db2759bb70966bbccaaa031d573f8519fc9737 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 14 Dec 2016 16:47:57 +0100
Subject: [PATCH 12/19] auth/credentials: let cli_credentials_parse_string()
always reset principal and realm
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
auth/credentials/credentials.c | 33 ++++++++++++++++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/auth/credentials/credentials.c b/auth/credentials/credentials.c
index cca772d..14c8403 100644
--- a/auth/credentials/credentials.c
+++ b/auth/credentials/credentials.c
@@ -797,9 +797,40 @@ _PUBLIC_ void cli_credentials_parse_string(struct cli_credentials *credentials,
|| (p = strchr_m(uname, '/'))
|| (p = strchr_m(uname, credentials->winbind_separator)))
{
+ const char *domain = NULL;
+
+ domain = uname;
*p = 0;
- cli_credentials_set_domain(credentials, uname, obtained);
uname = p+1;
+
+ if (obtained == credentials->realm_obtained &&
+ !strequal_m(credentials->domain, domain))
+ {
+ /*
+ * We need to undo a former set with the same level
+ * in order to get the expected result from
+ * cli_credentials_get_principal().
+ *
+ * But we only need to do that if the domain
+ * actually changes.
+ */
+ cli_credentials_set_realm(credentials, domain, obtained);
+ }
+ cli_credentials_set_domain(credentials, domain, obtained);
+ }
+ if (obtained == credentials->principal_obtained &&
+ !strequal_m(credentials->username, uname))
+ {
+ /*
+ * We need to undo a former set with the same level
+ * in order to get the expected result from
+ * cli_credentials_get_principal().
+ *
+ * But we only need to do that if the username
+ * actually changes.
+ */
+ credentials->principal_obtained = CRED_UNINITIALISED;
+ credentials->principal = NULL;
}
cli_credentials_set_username(credentials, uname, obtained);
}
--
1.9.1
From 11d088e621a9362e9af542e0579504dc0a51cec2 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 15 Dec 2016 14:12:31 +0100
Subject: [PATCH 13/19] tests/credentials.py: add tests to verify
realm/principal behaviour of cli_credentials_parse_string()
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
python/samba/tests/credentials.py | 50 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 49 insertions(+), 1 deletion(-)
diff --git a/python/samba/tests/credentials.py b/python/samba/tests/credentials.py
index 82a8ad9..d13d4df 100644
--- a/python/samba/tests/credentials.py
+++ b/python/samba/tests/credentials.py
@@ -210,7 +210,7 @@ class CredentialsTests(samba.tests.TestCaseInTempDir):
self.assertEqual(creds.is_anonymous(), False)
self.assertEqual(creds.authentication_requested(), True)
- def test_parse_username_with_domain(self):
+ def test_parse_username_with_domain_0(self):
creds = credentials.Credentials()
lp = samba.tests.env_loadparm()
os.environ["USER"] = "env_user"
@@ -223,6 +223,54 @@ class CredentialsTests(samba.tests.TestCaseInTempDir):
self.assertEqual(creds.is_anonymous(), False)
self.assertEqual(creds.authentication_requested(), True)
+ def test_parse_username_with_domain_1(self):
+ creds = credentials.Credentials()
+ lp = samba.tests.env_loadparm()
+ os.environ["USER"] = "env_user"
+ creds.guess(lp)
+ realm = "realm.example.com"
+ creds.set_realm(realm, credentials.UNINITIALISED)
+ self.assertEqual(creds.get_username(), "env_user")
+ self.assertEqual(creds.get_domain(), lp.get("workgroup").upper())
+ self.assertEqual(creds.get_realm(), realm.upper())
+ self.assertEqual(creds.get_principal(), "env_user@%s" % realm.upper())
+ creds.set_principal("unknown at realm.example.com")
+ self.assertEqual(creds.get_username(), "env_user")
+ self.assertEqual(creds.get_domain(), lp.get("workgroup").upper())
+ self.assertEqual(creds.get_realm(), realm.upper())
+ self.assertEqual(creds.get_principal(), "unknown at realm.example.com")
+ creds.parse_string("domain\user")
+ self.assertEqual(creds.get_username(), "user")
+ self.assertEqual(creds.get_domain(), "DOMAIN")
+ self.assertEqual(creds.get_realm(), realm.upper())
+ self.assertEqual(creds.get_principal(), "user at DOMAIN")
+ self.assertEqual(creds.is_anonymous(), False)
+ self.assertEqual(creds.authentication_requested(), True)
+
+ def test_parse_username_with_domain_2(self):
+ creds = credentials.Credentials()
+ lp = samba.tests.env_loadparm()
+ os.environ["USER"] = "env_user"
+ creds.guess(lp)
+ realm = "realm.example.com"
+ creds.set_realm(realm, credentials.SPECIFIED)
+ self.assertEqual(creds.get_username(), "env_user")
+ self.assertEqual(creds.get_domain(), lp.get("workgroup").upper())
+ self.assertEqual(creds.get_realm(), realm.upper())
+ self.assertEqual(creds.get_principal(), "env_user@%s" % realm.upper())
+ creds.set_principal("unknown at realm.example.com")
+ self.assertEqual(creds.get_username(), "env_user")
+ self.assertEqual(creds.get_domain(), lp.get("workgroup").upper())
+ self.assertEqual(creds.get_realm(), realm.upper())
+ self.assertEqual(creds.get_principal(), "unknown at realm.example.com")
+ creds.parse_string("domain\user")
+ self.assertEqual(creds.get_username(), "user")
+ self.assertEqual(creds.get_domain(), "DOMAIN")
+ self.assertEqual(creds.get_realm(), "DOMAIN")
+ self.assertEqual(creds.get_principal(), "user at DOMAIN")
+ self.assertEqual(creds.is_anonymous(), False)
+ self.assertEqual(creds.authentication_requested(), True)
+
def test_parse_username_with_realm(self):
creds = credentials.Credentials()
lp = samba.tests.env_loadparm()
--
1.9.1
From 51b765d66008f7184b08e6991ac713d5a38c8565 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Sun, 11 Dec 2016 22:50:53 +0100
Subject: [PATCH 14/19] auth/credentials: let cli_credentials_parse_file()
handle 'username' with cli_credentials_parse_string()
Some existing source3 tests (test_smbclient_s3.sh test_auth_file()) use a credentials file
that looks like this:
username=DOMAIN/username
password=password
domain=DOMAIN
This change allows us to parse the same.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
auth/credentials/credentials.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/auth/credentials/credentials.c b/auth/credentials/credentials.c
index 14c8403..0ffcc5c 100644
--- a/auth/credentials/credentials.c
+++ b/auth/credentials/credentials.c
@@ -1149,7 +1149,7 @@ _PUBLIC_ bool cli_credentials_parse_file(struct cli_credentials *cred, const cha
if (strwicmp("password", param) == 0) {
cli_credentials_set_password(cred, val, obtained);
} else if (strwicmp("username", param) == 0) {
- cli_credentials_set_username(cred, val, obtained);
+ cli_credentials_parse_string(cred, val, obtained);
} else if (strwicmp("domain", param) == 0) {
cli_credentials_set_domain(cred, val, obtained);
} else if (strwicmp("realm", param) == 0) {
--
1.9.1
From 11773e4c1a30d37d8dfa86751b1182270980915f Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 15 Dec 2016 14:01:35 +0100
Subject: [PATCH 15/19] tests/credentials.py: verify the new
cli_credentials_parse_file() 'username' parsing
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
python/samba/tests/credentials.py | 49 +++++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/python/samba/tests/credentials.py b/python/samba/tests/credentials.py
index d13d4df..7aaa711 100644
--- a/python/samba/tests/credentials.py
+++ b/python/samba/tests/credentials.py
@@ -178,6 +178,55 @@ class CredentialsTests(samba.tests.TestCaseInTempDir):
self.assertEqual(self.creds.get_password(), password)
self.assertEqual(self.creds.get_domain(), domain.upper())
self.assertEqual(self.creds.get_realm(), realm.upper())
+ self.assertEqual(self.creds.get_principal(), "%s@%s" % (username, realm.upper()))
+ self.assertEqual(self.creds.is_anonymous(), False)
+ self.assertEqual(self.creds.authentication_requested(), True)
+ os.unlink(passwd_file_name)
+
+ def test_parse_file_2(self):
+ realm="realm.example.com"
+ domain="dom"
+ password="pass"
+ username="user"
+
+ passwd_file_name = os.path.join(self.tempdir, "parse_file")
+ passwd_file_fd = open(passwd_file_name, 'wx')
+ passwd_file_fd.write("realm=%s\n" % realm)
+ passwd_file_fd.write("domain=%s\n" % domain)
+ passwd_file_fd.write("username=%s\\%s\n" % (domain, username))
+ passwd_file_fd.write("password=%s\n" % password)
+ passwd_file_fd.close()
+ self.creds.parse_file(passwd_file_name)
+ self.assertEqual(self.creds.get_username(), username)
+ self.assertEqual(self.creds.get_password(), password)
+ self.assertEqual(self.creds.get_domain(), domain.upper())
+ self.assertEqual(self.creds.get_realm(), realm.upper())
+ self.assertEqual(self.creds.get_principal(), "%s@%s" % (username, realm.upper()))
+ self.assertEqual(self.creds.is_anonymous(), False)
+ self.assertEqual(self.creds.authentication_requested(), True)
+ os.unlink(passwd_file_name)
+
+ def test_parse_file_3(self):
+ realm="realm.example.com"
+ domain="domain"
+ password="password"
+ username="username"
+
+ userdom="userdom"
+
+ passwd_file_name = os.path.join(self.tempdir, "parse_file")
+ passwd_file_fd = open(passwd_file_name, 'wx')
+ passwd_file_fd.write("realm=%s\n" % realm)
+ passwd_file_fd.write("domain=%s\n" % domain)
+ passwd_file_fd.write("username=%s/%s\n" % (userdom, username))
+ passwd_file_fd.write("password=%s\n" % password)
+ passwd_file_fd.close()
+ self.creds.parse_file(passwd_file_name)
+ self.assertEqual(self.creds.get_username(), username)
+ self.assertEqual(self.creds.get_password(), password)
+ self.assertEqual(self.creds.get_domain(), userdom.upper())
+ self.assertEqual(self.creds.get_realm(), userdom.upper())
+ self.assertEqual(self.creds.get_principal(), "%s@%s" % (username, userdom.upper()))
self.assertEqual(self.creds.is_anonymous(), False)
self.assertEqual(self.creds.authentication_requested(), True)
os.unlink(passwd_file_name)
--
1.9.1
From c296d7f38cc8be1b689d4251be55c0c5cac501e4 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 15 Dec 2016 12:41:58 +0100
Subject: [PATCH 16/19] auth/credentials: change the parsing order of
cli_credentials_parse_file()
We now first just remember the domain, realm, username, password values
(the last value wins).
At the end we call cli_credentials_set_{realm,domain,password}()
followed by cli_credentials_parse_string() for 'username'.
It means the last 'username' line beats the domain, realm or password lines, e.g.:
username=USERDOMAIN\username
domain=DOMAIN
will result in cli_credentials_get_domain() returning "USERDOMAIN" instead of
DOMAIN.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
auth/credentials/credentials.c | 54 ++++++++++++++++++++++++++++++++++++++----
1 file changed, 49 insertions(+), 5 deletions(-)
diff --git a/auth/credentials/credentials.c b/auth/credentials/credentials.c
index 0ffcc5c..9a935c6 100644
--- a/auth/credentials/credentials.c
+++ b/auth/credentials/credentials.c
@@ -1117,6 +1117,10 @@ _PUBLIC_ bool cli_credentials_parse_file(struct cli_credentials *cred, const cha
char *ptr, *val, *param;
char **lines;
int i, numlines;
+ const char *realm = NULL;
+ const char *domain = NULL;
+ const char *password = NULL;
+ const char *username = NULL;
lines = file_lines_load(file, &numlines, 0, NULL);
@@ -1147,17 +1151,57 @@ _PUBLIC_ bool cli_credentials_parse_file(struct cli_credentials *cred, const cha
val++;
if (strwicmp("password", param) == 0) {
- cli_credentials_set_password(cred, val, obtained);
+ password = val;
} else if (strwicmp("username", param) == 0) {
- cli_credentials_parse_string(cred, val, obtained);
+ username = val;
} else if (strwicmp("domain", param) == 0) {
- cli_credentials_set_domain(cred, val, obtained);
+ domain = val;
} else if (strwicmp("realm", param) == 0) {
- cli_credentials_set_realm(cred, val, obtained);
+ realm = val;
}
- memset(lines[i], 0, len);
+
+ /*
+ * We need to readd '=' in order to let
+ * the strlen() work in the last loop
+ * that clears the memory.
+ */
+ *ptr = '=';
+ }
+
+ if (realm != NULL && strlen(realm) != 0) {
+ /*
+ * only overwrite with a valid string
+ */
+ cli_credentials_set_realm(cred, realm, obtained);
+ }
+
+ if (domain != NULL && strlen(domain) != 0) {
+ /*
+ * only overwrite with a valid string
+ */
+ cli_credentials_set_domain(cred, domain, obtained);
}
+ if (password != NULL) {
+ /*
+ * Here we allow "".
+ */
+ cli_credentials_set_password(cred, password, obtained);
+ }
+
+ if (username != NULL) {
+ /*
+ * The last "username" line takes preference
+ * if the string also contains domain, realm or
+ * password.
+ */
+ cli_credentials_parse_string(cred, username, obtained);
+ }
+
+ for (i = 0; i < numlines; i++) {
+ len = strlen(lines[i]);
+ memset(lines[i], 0, len);
+ }
talloc_free(lines);
return true;
--
1.9.1
From 7f3d9e3758ab2037abea573f0bcb9151294a4b19 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 15 Dec 2016 15:30:28 +0100
Subject: [PATCH 17/19] tests/credentials.py: demonstrate the last 'username'
line of creds.parse_file() beats other lines
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
python/samba/tests/credentials.py | 50 +++++++++++++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/python/samba/tests/credentials.py b/python/samba/tests/credentials.py
index 7aaa711..4e5746e 100644
--- a/python/samba/tests/credentials.py
+++ b/python/samba/tests/credentials.py
@@ -231,6 +231,56 @@ class CredentialsTests(samba.tests.TestCaseInTempDir):
self.assertEqual(self.creds.authentication_requested(), True)
os.unlink(passwd_file_name)
+ def test_parse_file_4(self):
+ realm="realm.example.com"
+ domain="domain"
+ password="password"
+ username="username"
+
+ userdom="userdom"
+
+ passwd_file_name = os.path.join(self.tempdir, "parse_file")
+ passwd_file_fd = open(passwd_file_name, 'wx')
+ passwd_file_fd.write("username=%s\\%s%%%s\n" % (userdom, username, password))
+ passwd_file_fd.write("realm=ignorerealm\n")
+ passwd_file_fd.write("domain=ignoredomain\n")
+ passwd_file_fd.write("password=ignorepassword\n")
+ passwd_file_fd.close()
+ self.creds.parse_file(passwd_file_name)
+ self.assertEqual(self.creds.get_username(), username)
+ self.assertEqual(self.creds.get_password(), password)
+ self.assertEqual(self.creds.get_domain(), userdom.upper())
+ self.assertEqual(self.creds.get_realm(), userdom.upper())
+ self.assertEqual(self.creds.get_principal(), "%s@%s" % (username, userdom.upper()))
+ self.assertEqual(self.creds.is_anonymous(), False)
+ self.assertEqual(self.creds.authentication_requested(), True)
+ os.unlink(passwd_file_name)
+
+ def test_parse_file_5(self):
+ realm="realm.example.com"
+ domain="domain"
+ password="password"
+ username="username"
+
+ userdom="userdom"
+
+ passwd_file_name = os.path.join(self.tempdir, "parse_file")
+ passwd_file_fd = open(passwd_file_name, 'wx')
+ passwd_file_fd.write("realm=ignorerealm\n")
+ passwd_file_fd.write("username=%s\\%s%%%s\n" % (userdom, username, password))
+ passwd_file_fd.write("domain=ignoredomain\n")
+ passwd_file_fd.write("password=ignorepassword\n")
+ passwd_file_fd.close()
+ self.creds.parse_file(passwd_file_name)
+ self.assertEqual(self.creds.get_username(), username)
+ self.assertEqual(self.creds.get_password(), password)
+ self.assertEqual(self.creds.get_domain(), userdom.upper())
+ self.assertEqual(self.creds.get_realm(), userdom.upper())
+ self.assertEqual(self.creds.get_principal(), "%s@%s" % (username, userdom.upper()))
+ self.assertEqual(self.creds.is_anonymous(), False)
+ self.assertEqual(self.creds.authentication_requested(), True)
+ os.unlink(passwd_file_name)
+
def test_parse_username_0(self):
creds = credentials.Credentials()
lp = samba.tests.env_loadparm()
--
1.9.1
From a712bce67f1a6eddcb56f805221f3dcccc351938 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 9 Dec 2016 16:04:38 +0100
Subject: [PATCH 18/19] s3:popt_common: let POPT_COMMON_CREDENTIALS imply
logfile and conffile loading
All users of POPT_COMMON_CREDENTIALS basically need the same logic,
while some ignore a broken smb.conf and some complain about it.
This will allow the future usage of config options in the
credential post processing.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
source3/client/client.c | 11 +----------
source3/include/popt_common.h | 1 +
source3/lib/popt_common.c | 25 +++++++++++++++++++++++++
source3/rpcclient/rpcclient.c | 15 ---------------
source3/utils/regedit.c | 5 -----
source3/utils/smbcacls.c | 5 ++---
source3/utils/smbcquotas.c | 12 ------------
source3/utils/smbtree.c | 5 ++---
8 files changed, 31 insertions(+), 48 deletions(-)
diff --git a/source3/client/client.c b/source3/client/client.c
index 82521288..cde9776 100644
--- a/source3/client/client.c
+++ b/source3/client/client.c
@@ -5765,6 +5765,7 @@ int main(int argc,char *argv[])
lp_set_cmdline("log level", "1");
+ popt_common_credentials_set_ignore_missing_conf();
popt_common_credentials_set_delay_post();
/* skip argv(0) */
@@ -5901,16 +5902,6 @@ int main(int argc,char *argv[])
poptGetArg(pc));
}
- if ( override_logfile )
- setup_logging( lp_logfile(talloc_tos()), DEBUG_FILE );
-
- if (!lp_load_client(get_dyn_CONFIGFILE())) {
- fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n",
- argv[0], get_dyn_CONFIGFILE());
- }
-
- load_interfaces();
-
if (service_opt && service) {
size_t len;
diff --git a/source3/include/popt_common.h b/source3/include/popt_common.h
index ec7568c..2abfa04 100644
--- a/source3/include/popt_common.h
+++ b/source3/include/popt_common.h
@@ -50,6 +50,7 @@ extern const struct poptOption popt_common_dynconfig[];
extern struct user_auth_info *cmdline_auth_info;
+void popt_common_credentials_set_ignore_missing_conf(void);
void popt_common_credentials_set_delay_post(void);
void popt_common_credentials_post(void);
void popt_burn_cmdline_password(int argc, char *argv[]);
diff --git a/source3/lib/popt_common.c b/source3/lib/popt_common.c
index b2fd39c..e229ad2 100644
--- a/source3/lib/popt_common.c
+++ b/source3/lib/popt_common.c
@@ -348,8 +348,14 @@ static void get_credentials_file(struct user_auth_info *auth_info,
*/
struct user_auth_info *cmdline_auth_info;
+static bool popt_common_credentials_ignore_missing_conf;
static bool popt_common_credentials_delay_post;
+void popt_common_credentials_set_ignore_missing_conf(void)
+{
+ popt_common_credentials_delay_post = true;
+}
+
void popt_common_credentials_set_delay_post(void)
{
popt_common_credentials_delay_post = true;
@@ -412,6 +418,25 @@ static void popt_common_credentials_callback(poptContext con,
}
if (reason == POPT_CALLBACK_REASON_POST) {
+ bool ok;
+
+ if (override_logfile) {
+ setup_logging(lp_logfile(talloc_tos()), DEBUG_FILE );
+ }
+
+ ok = lp_load_client(get_dyn_CONFIGFILE());
+ if (!ok) {
+ const char *pname = poptGetInvocationName(con);
+
+ fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n",
+ pname, get_dyn_CONFIGFILE());
+ if (!popt_common_credentials_ignore_missing_conf) {
+ exit(1);
+ }
+ }
+
+ load_interfaces();
+
if (popt_common_credentials_delay_post) {
return;
}
diff --git a/source3/rpcclient/rpcclient.c b/source3/rpcclient/rpcclient.c
index 138fdba..9faf01b 100644
--- a/source3/rpcclient/rpcclient.c
+++ b/source3/rpcclient/rpcclient.c
@@ -949,7 +949,6 @@ out_free:
char *user, *domain, *q;
const char *host;
int signing_state = SMB_SIGNING_IPC_DEFAULT;
- bool ok;
/* make sure the vars that get altered (4th field) are in
a fixed location or certain compilers complain */
@@ -1016,17 +1015,6 @@ out_free:
popt_burn_cmdline_password(argc, argv);
rpcclient_auth_info = cmdline_auth_info;
- /* Load smb.conf file */
-
- ok = lp_load_global(get_dyn_CONFIGFILE());
- if (!ok) {
- fprintf(stderr,
- "Can't load %s - run testparm to debug it\n",
- get_dyn_CONFIGFILE());
- result = 1;
- goto done;
- }
-
nt_status = messaging_init_client(talloc_autofree_context(),
samba_tevent_context_init(talloc_autofree_context()),
&rpcclient_msg_ctx);
@@ -1045,9 +1033,6 @@ out_free:
goto done;
}
- /* We must load interfaces after we load the smb.conf */
- load_interfaces();
-
if (!init_names()) {
result = 1;
goto done;
diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c
index 476897f..14e75c2 100644
--- a/source3/utils/regedit.c
+++ b/source3/utils/regedit.c
@@ -781,11 +781,6 @@ int main(int argc, const char **argv)
/* TODO */
}
- if (!lp_load_global(get_dyn_CONFIGFILE())) {
- DEBUG(0, ("ERROR loading config file...\n"));
- exit(1);
- }
-
rv = reg_open_samba3(frame, &ctx);
if (!W_ERROR_IS_OK(rv)) {
fprintf(stderr, "Unable to open registry: %s\n",
diff --git a/source3/utils/smbcacls.c b/source3/utils/smbcacls.c
index 7705eb4..255ff97 100644
--- a/source3/utils/smbcacls.c
+++ b/source3/utils/smbcacls.c
@@ -831,6 +831,8 @@ int main(int argc, char *argv[])
setlinebuf(stdout);
+ popt_common_credentials_set_ignore_missing_conf();
+
pc = poptGetContext("smbcacls", argc, argv_const, long_options, 0);
poptSetOtherOptionHelp(pc, "//server1/share1 filename\nACLs look like: "
@@ -894,9 +896,6 @@ int main(int argc, char *argv[])
return -1;
}
- lp_load_global(get_dyn_CONFIGFILE());
- load_interfaces();
-
filename = talloc_strdup(frame, poptGetArg(pc));
if (!filename) {
return -1;
diff --git a/source3/utils/smbcquotas.c b/source3/utils/smbcquotas.c
index ba80926..a1cf70a1 100644
--- a/source3/utils/smbcquotas.c
+++ b/source3/utils/smbcquotas.c
@@ -575,7 +575,6 @@ int main(int argc, char *argv[])
static bool test_args = False;
struct cli_state *cli;
bool fix_user = False;
- bool ok;
SMB_NTQUOTA_STRUCT qt;
TALLOC_CTX *frame = talloc_stackframe();
poptContext pc;
@@ -700,17 +699,6 @@ FSQFLAGS:QUOTA_ENABLED/DENY_DISK/LOG_SOFTLIMIT/LOG_HARD_LIMIT", "SETSTRING" },
poptFreeContext(pc);
popt_burn_cmdline_password(argc, argv);
- ok = lp_load_global(get_dyn_CONFIGFILE());
- if (!ok) {
- DBG_ERR("ERROR: Loading config file %s - "
- "run testparm to debug it\n",
- get_dyn_CONFIGFILE());
- exit(EXIT_PARSE_ERROR);
- }
-
- /* We must load interfaces after we load the smb.conf */
- load_interfaces();
-
string_replace(path, '/', '\\');
server = SMB_STRDUP(path+2);
diff --git a/source3/utils/smbtree.c b/source3/utils/smbtree.c
index 2f11dce..ba7b318 100644
--- a/source3/utils/smbtree.c
+++ b/source3/utils/smbtree.c
@@ -307,15 +307,14 @@ int main(int argc, char *argv[])
setup_logging(argv[0], DEBUG_STDERR);
+ popt_common_credentials_set_ignore_missing_conf();
+
pc = poptGetContext("smbtree", argc, argv_const, long_options,
POPT_CONTEXT_KEEP_FIRST);
while(poptGetNextOpt(pc) != -1);
poptFreeContext(pc);
popt_burn_cmdline_password(argc, argv);
- lp_load_global(get_dyn_CONFIGFILE());
- load_interfaces();
-
/* Now do our stuff */
if (!print_tree(cmdline_auth_info)) {
--
1.9.1
From 922fc219f1b891818f2d8b880f5033323ae7d28d Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 28 Oct 2016 12:14:37 +0200
Subject: [PATCH 19/19] s3:user_auth_info: let struct user_auth_info use struct
cli_credentials internally
This way we can have a very simple get_cmdline_auth_info_creds() function,
which can be used pass cli_credentials down the stack instead of
constantly translating from user_auth_info to cli_credentials, while
loosing information.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
source3/include/auth_info.h | 6 +
source3/lib/popt_common.c | 182 +----------------------
source3/lib/util_cmdline.c | 346 +++++++++++++++++++++++++++++---------------
3 files changed, 245 insertions(+), 289 deletions(-)
diff --git a/source3/include/auth_info.h b/source3/include/auth_info.h
index 04ac422..c6f71ad 100644
--- a/source3/include/auth_info.h
+++ b/source3/include/auth_info.h
@@ -23,6 +23,9 @@
struct user_auth_info;
struct user_auth_info *user_auth_info_init(TALLOC_CTX *mem_ctx);
+void set_cmdline_auth_info_guess(struct user_auth_info *auth_info);
+void set_cmdline_auth_info_from_file(struct user_auth_info *auth_info,
+ const char *filename);
const char *get_cmdline_auth_info_username(const struct user_auth_info *auth_info);
void set_cmdline_auth_info_username(struct user_auth_info *auth_info,
const char *username);
@@ -59,4 +62,7 @@ bool get_cmdline_auth_info_use_machine_account(const struct user_auth_info *auth
bool set_cmdline_auth_info_machine_account_creds(struct user_auth_info *auth_info);
void set_cmdline_auth_info_getpass(struct user_auth_info *auth_info);
+struct cli_credentials *get_cmdline_auth_info_creds(
+ const struct user_auth_info *auth_info);
+
#endif /* _AUTH_INFO_H */
diff --git a/source3/lib/popt_common.c b/source3/lib/popt_common.c
index e229ad2..3589a4f 100644
--- a/source3/lib/popt_common.c
+++ b/source3/lib/popt_common.c
@@ -21,7 +21,6 @@
*/
#include "includes.h"
-#include "system/filesys.h"
#include "popt_common.h"
#include "lib/param/param.h"
@@ -211,131 +210,6 @@ struct poptOption popt_common_option[] = {
POPT_TABLEEND
};
-/****************************************************************************
- * get a password from a a file or file descriptor
- * exit on failure
- * ****************************************************************************/
-
-static void get_password_file(struct user_auth_info *auth_info)
-{
- int fd = -1;
- char *p;
- bool close_it = False;
- char *spec = NULL;
- char pass[128];
-
- if ((p = getenv("PASSWD_FD")) != NULL) {
- if (asprintf(&spec, "descriptor %s", p) < 0) {
- return;
- }
- sscanf(p, "%d", &fd);
- close_it = false;
- } else if ((p = getenv("PASSWD_FILE")) != NULL) {
- fd = open(p, O_RDONLY, 0);
- spec = SMB_STRDUP(p);
- if (fd < 0) {
- fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
- spec, strerror(errno));
- exit(1);
- }
- close_it = True;
- }
-
- if (fd < 0) {
- fprintf(stderr, "fd = %d, < 0\n", fd);
- exit(1);
- }
-
- for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
- p && p - pass < sizeof(pass);) {
- switch (read(fd, p, 1)) {
- case 1:
- if (*p != '\n' && *p != '\0') {
- *++p = '\0'; /* advance p, and null-terminate pass */
- break;
- }
- case 0:
- if (p - pass) {
- *p = '\0'; /* null-terminate it, just in case... */
- p = NULL; /* then force the loop condition to become false */
- break;
- } else {
- fprintf(stderr, "Error reading password from file %s: %s\n",
- spec, "empty password\n");
- SAFE_FREE(spec);
- exit(1);
- }
-
- default:
- fprintf(stderr, "Error reading password from file %s: %s\n",
- spec, strerror(errno));
- SAFE_FREE(spec);
- exit(1);
- }
- }
- SAFE_FREE(spec);
-
- set_cmdline_auth_info_password(auth_info, pass);
- if (close_it) {
- close(fd);
- }
-}
-
-static void get_credentials_file(struct user_auth_info *auth_info,
- const char *file)
-{
- FILE *auth;
- fstring buf;
- uint16_t len = 0;
- char *ptr, *val, *param;
-
- auth = fopen(file, "r");
- if (auth == NULL) {
- /* fail if we can't open the credentials file */
- d_printf("ERROR: Unable to open credentials file!\n");
- exit(-1);
- }
-
- while (!feof(auth))
- {
- /* get a line from the file */
- if (!fgets(buf, sizeof(buf), auth))
- continue;
- len = strlen(buf);
-
- if ((len) && (buf[len-1]=='\n'))
- {
- buf[len-1] = '\0';
- len--;
- }
- if (len == 0)
- continue;
-
- /* break up the line into parameter & value.
- * will need to eat a little whitespace possibly */
- param = buf;
- if (!(ptr = strchr_m (buf, '=')))
- continue;
-
- val = ptr+1;
- *ptr = '\0';
-
- /* eat leading white space */
- while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
- val++;
-
- if (strwicmp("password", param) == 0) {
- set_cmdline_auth_info_password(auth_info, val);
- } else if (strwicmp("username", param) == 0) {
- set_cmdline_auth_info_username(auth_info, val);
- } else if (strwicmp("domain", param) == 0) {
- set_cmdline_auth_info_domain(auth_info, val);
- }
- memset(buf, 0, sizeof(buf));
- }
- fclose(auth);
-}
-
/* Handle command line options:
* -U,--user
* -A,--authentication-file
@@ -384,36 +258,12 @@ static void popt_common_credentials_callback(poptContext con,
struct user_auth_info *auth_info = cmdline_auth_info;
if (reason == POPT_CALLBACK_REASON_PRE) {
+ auth_info = user_auth_info_init(talloc_autofree_context());
if (auth_info == NULL) {
- auth_info = user_auth_info_init(talloc_autofree_context());
- if (auth_info == NULL) {
- fprintf(stderr, "user_auth_info_init() failed\n");
- exit(1);
- }
- cmdline_auth_info = auth_info;
- }
-
- set_cmdline_auth_info_username(auth_info, "GUEST");
-
- if (getenv("LOGNAME")) {
- set_cmdline_auth_info_username(auth_info,
- getenv("LOGNAME"));
- }
-
- if (getenv("USER")) {
- set_cmdline_auth_info_username(auth_info,
- getenv("USER"));
- }
-
- if (getenv("PASSWD")) {
- set_cmdline_auth_info_password(auth_info,
- getenv("PASSWD"));
- }
-
- if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
- get_password_file(auth_info);
+ fprintf(stderr, "user_auth_info_init() failed\n");
+ exit(1);
}
-
+ cmdline_auth_info = auth_info;
return;
}
@@ -437,6 +287,8 @@ static void popt_common_credentials_callback(poptContext con,
load_interfaces();
+ set_cmdline_auth_info_guess(auth_info);
+
if (popt_common_credentials_delay_post) {
return;
}
@@ -447,29 +299,11 @@ static void popt_common_credentials_callback(poptContext con,
switch(opt->val) {
case 'U':
- {
- char *lp;
- char *puser = SMB_STRDUP(arg);
-
- if ((lp=strchr_m(puser,'%'))) {
- size_t len;
- *lp = '\0';
- set_cmdline_auth_info_username(auth_info,
- puser);
- set_cmdline_auth_info_password(auth_info,
- lp+1);
- len = strlen(lp+1);
- memset(lp + 1, '\0', len);
- } else {
- set_cmdline_auth_info_username(auth_info,
- puser);
- }
- SAFE_FREE(puser);
- }
+ set_cmdline_auth_info_username(auth_info, arg);
break;
case 'A':
- get_credentials_file(auth_info, arg);
+ set_cmdline_auth_info_from_file(auth_info, arg);
break;
case 'k':
diff --git a/source3/lib/util_cmdline.c b/source3/lib/util_cmdline.c
index 68ba7aa..6c98b44 100644
--- a/source3/lib/util_cmdline.c
+++ b/source3/lib/util_cmdline.c
@@ -24,6 +24,10 @@
#include "includes.h"
#include "auth_info.h"
#include "secrets.h"
+#include "param/param.h"
+#include "librpc/gen_ndr/samr.h"
+#include "auth/credentials/credentials.h"
+#include "auth/gensec/gensec.h"
/**************************************************************************n
Code to cope with username/password auth options from the commandline.
@@ -31,129 +35,174 @@
****************************************************************************/
struct user_auth_info {
- char *username;
- char *domain;
- char *password;
+ struct cli_credentials *creds;
+ struct loadparm_context *lp_ctx;
bool got_pass;
- bool use_kerberos;
int signing_state;
bool smb_encrypt;
bool use_machine_account;
- bool fallback_after_kerberos;
- bool use_ccache;
bool use_pw_nt_hash;
+ char *pw_nt_hash;
};
struct user_auth_info *user_auth_info_init(TALLOC_CTX *mem_ctx)
{
- struct user_auth_info *result;
+ struct user_auth_info *result = NULL;
result = talloc_zero(mem_ctx, struct user_auth_info);
if (result == NULL) {
return NULL;
}
+ result->lp_ctx = loadparm_init_s3(result, loadparm_s3_helpers());
+ if (result->lp_ctx == NULL) {
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ result->creds = cli_credentials_init(result);
+ if (result->creds == NULL) {
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ cli_credentials_set_conf(result->creds, result->lp_ctx);
+
result->signing_state = SMB_SIGNING_DEFAULT;
return result;
}
-const char *get_cmdline_auth_info_username(const struct user_auth_info *auth_info)
+void set_cmdline_auth_info_guess(struct user_auth_info *auth_info)
{
- if (!auth_info->username) {
- return "";
- }
- return auth_info->username;
+ /*
+ * Note that cli_credentials_guess() calls
+ * cli_credentials_set_conf() again, which will
+ * hopefully cope with a reloaded smb.conf.
+ */
+ cli_credentials_set_username(auth_info->creds, "GUEST", CRED_GUESS_ENV);
+ cli_credentials_guess(auth_info->creds, auth_info->lp_ctx);
}
-void set_cmdline_auth_info_username(struct user_auth_info *auth_info,
- const char *username)
+void set_cmdline_auth_info_from_file(struct user_auth_info *auth_info,
+ const char *filename)
{
- char *s;
- char *p;
- bool contains_domain = false;
-
- s = talloc_strdup(auth_info, username);
- if (s == NULL) {
- exit(ENOMEM);
- }
+ bool ok;
- p = strchr_m(s, '\\');
- if (p != NULL) {
- contains_domain = true;
- }
- if (!contains_domain) {
- p = strchr_m(s, '/');
- if (p != NULL) {
- contains_domain = true;
- }
- }
- if (!contains_domain) {
- char sep = *lp_winbind_separator();
-
- if (sep != '\0') {
- p = strchr_m(s, *lp_winbind_separator());
- if (p != NULL) {
- contains_domain = true;
- }
- }
+ ok = cli_credentials_parse_file(auth_info->creds, filename,
+ CRED_SPECIFIED);
+ if (!ok) {
+ exit(EIO);
}
+}
- if (contains_domain) {
- *p = '\0';
- username = p + 1;
+const char *get_cmdline_auth_info_username(const struct user_auth_info *auth_info)
+{
+ const char *username = NULL;
- /* s is now the workgroup part */
- set_cmdline_auth_info_domain(auth_info, s);
+ username = cli_credentials_get_username(auth_info->creds);
+ if (username == NULL) {
+ return "";
}
- TALLOC_FREE(auth_info->username);
- auth_info->username = talloc_strdup(auth_info, username);
+ return username;
+}
- TALLOC_FREE(s);
+void set_cmdline_auth_info_username(struct user_auth_info *auth_info,
+ const char *username)
+{
+ const char *new_val = NULL;
- if (!auth_info->username) {
+ cli_credentials_parse_string(auth_info->creds,
+ username,
+ CRED_SPECIFIED);
+ new_val = cli_credentials_get_username(auth_info->creds);
+ if (username != NULL && new_val == NULL) {
exit(ENOMEM);
}
+
+ if (strchr_m(username, '%') != NULL) {
+ auth_info->got_pass = true;
+ }
}
const char *get_cmdline_auth_info_domain(const struct user_auth_info *auth_info)
{
- if (!auth_info->domain) {
+ const char *domain = NULL;
+
+ domain = cli_credentials_get_domain(auth_info->creds);
+ if (domain == NULL) {
return "";
}
- return auth_info->domain;
+
+ return domain;
}
void set_cmdline_auth_info_domain(struct user_auth_info *auth_info,
const char *domain)
{
- TALLOC_FREE(auth_info->domain);
- auth_info->domain = talloc_strdup(auth_info, domain);
- if (!auth_info->domain) {
+ bool ok;
+
+ ok = cli_credentials_set_domain(auth_info->creds, domain, CRED_SPECIFIED);
+ if (!ok) {
exit(ENOMEM);
}
}
const char *get_cmdline_auth_info_password(const struct user_auth_info *auth_info)
{
- if (!auth_info->password) {
+ const char *password = NULL;
+
+ if (auth_info->pw_nt_hash != NULL) {
+ return auth_info->pw_nt_hash;
+ }
+
+ if (auth_info->use_pw_nt_hash) {
+ struct user_auth_info *ai =
+ discard_const_p(struct user_auth_info, auth_info);
+ struct samr_Password *nt_hash = NULL;
+
+ nt_hash = cli_credentials_get_nt_hash(ai->creds,
+ ai);
+ if (nt_hash == NULL) {
+ return "";
+ }
+
+ ai->pw_nt_hash = hex_encode_talloc(ai,
+ nt_hash->hash,
+ sizeof(nt_hash->hash));
+ TALLOC_FREE(nt_hash);
+ if (ai->pw_nt_hash == NULL) {
+ return "";
+ }
+
+ return auth_info->pw_nt_hash;
+ }
+
+ password = cli_credentials_get_password(auth_info->creds);
+ if (password == NULL) {
return "";
}
- return auth_info->password;
+
+ return password;
}
void set_cmdline_auth_info_password(struct user_auth_info *auth_info,
const char *password)
{
- TALLOC_FREE(auth_info->password);
- if (password == NULL) {
- password = "";
+ bool ok;
+
+ auth_info->got_pass = true;
+
+ if (password != NULL && strlen(password) == 0) {
+ password = NULL;
}
- auth_info->password = talloc_strdup(auth_info, password);
- if (!auth_info->password) {
+
+ ok = cli_credentials_set_password(auth_info->creds,
+ password,
+ CRED_SPECIFIED);
+ if (!ok) {
exit(ENOMEM);
}
- auth_info->got_pass = true;
}
bool set_cmdline_auth_info_signing_state(struct user_auth_info *auth_info,
@@ -189,18 +238,31 @@ int get_cmdline_auth_info_signing_state(const struct user_auth_info *auth_info)
void set_cmdline_auth_info_use_ccache(struct user_auth_info *auth_info, bool b)
{
- auth_info->use_ccache = b;
+ uint32_t gensec_features;
+
+ gensec_features = cli_credentials_get_gensec_features(auth_info->creds);
+ gensec_features |= GENSEC_FEATURE_NTLM_CCACHE;
+ cli_credentials_set_gensec_features(auth_info->creds, gensec_features);
}
bool get_cmdline_auth_info_use_ccache(const struct user_auth_info *auth_info)
{
- return auth_info->use_ccache;
+ uint32_t gensec_features;
+
+ gensec_features = cli_credentials_get_gensec_features(auth_info->creds);
+ if (gensec_features & GENSEC_FEATURE_NTLM_CCACHE) {
+ return true;
+ }
+
+ return false;
}
void set_cmdline_auth_info_use_pw_nt_hash(struct user_auth_info *auth_info,
bool b)
{
+ TALLOC_FREE(auth_info->pw_nt_hash);
auth_info->use_pw_nt_hash = b;
+ cli_credentials_set_password_will_be_nt_hash(auth_info->creds, b);
}
bool get_cmdline_auth_info_use_pw_nt_hash(
@@ -212,29 +274,73 @@ bool get_cmdline_auth_info_use_pw_nt_hash(
void set_cmdline_auth_info_use_kerberos(struct user_auth_info *auth_info,
bool b)
{
- auth_info->use_kerberos = b;
+ enum credentials_use_kerberos krb5_state;
+
+ if (b) {
+ krb5_state = CRED_MUST_USE_KERBEROS;
+ } else {
+ krb5_state = CRED_DONT_USE_KERBEROS;
+ }
+
+ cli_credentials_set_kerberos_state(auth_info->creds, krb5_state);
}
bool get_cmdline_auth_info_use_kerberos(const struct user_auth_info *auth_info)
{
- return auth_info->use_kerberos;
+ enum credentials_use_kerberos krb5_state;
+
+ krb5_state = cli_credentials_get_kerberos_state(auth_info->creds);
+
+ if (krb5_state == CRED_MUST_USE_KERBEROS) {
+ return true;
+ }
+
+ return false;
}
void set_cmdline_auth_info_fallback_after_kerberos(struct user_auth_info *auth_info,
bool b)
{
- auth_info->fallback_after_kerberos = b;
+ enum credentials_use_kerberos krb5_state;
+
+ krb5_state = cli_credentials_get_kerberos_state(auth_info->creds);
+
+ switch (krb5_state) {
+ case CRED_MUST_USE_KERBEROS:
+ if (b) {
+ krb5_state = CRED_AUTO_USE_KERBEROS;
+ }
+ break;
+ case CRED_AUTO_USE_KERBEROS:
+ if (!b) {
+ krb5_state = CRED_MUST_USE_KERBEROS;
+ }
+ break;
+ case CRED_DONT_USE_KERBEROS:
+ /* nothing to do */
+ break;
+ }
+
+ cli_credentials_set_kerberos_state(auth_info->creds, krb5_state);
}
bool get_cmdline_auth_info_fallback_after_kerberos(const struct user_auth_info *auth_info)
{
- return auth_info->fallback_after_kerberos;
+ enum credentials_use_kerberos krb5_state;
+
+ krb5_state = cli_credentials_get_kerberos_state(auth_info->creds);
+
+ if (krb5_state == CRED_AUTO_USE_KERBEROS) {
+ return true;
+ }
+
+ return false;
}
/* This should only be used by lib/popt_common.c JRA */
void set_cmdline_auth_info_use_krb5_ticket(struct user_auth_info *auth_info)
{
- auth_info->use_kerberos = true;
+ set_cmdline_auth_info_use_kerberos(auth_info, true);
auth_info->got_pass = true;
}
@@ -246,6 +352,8 @@ void set_cmdline_auth_info_smb_encrypt(struct user_auth_info *auth_info)
void set_cmdline_auth_info_use_machine_account(struct user_auth_info *auth_info)
{
+ cli_credentials_set_machine_account_pending(auth_info->creds,
+ auth_info->lp_ctx);
auth_info->use_machine_account = true;
}
@@ -266,54 +374,67 @@ bool get_cmdline_auth_info_use_machine_account(const struct user_auth_info *auth
bool set_cmdline_auth_info_machine_account_creds(struct user_auth_info *auth_info)
{
- char *pass = NULL;
- char *account = NULL;
- const char *realm = lp_realm();
- int rc;
-
+ struct db_context *db_ctx = NULL;
+ NTSTATUS status;
if (!get_cmdline_auth_info_use_machine_account(auth_info)) {
return false;
}
- if (!secrets_init()) {
+ db_ctx = secrets_db_ctx();
+ if (db_ctx == NULL) {
d_printf("ERROR: Unable to open secrets database\n");
return false;
}
- if (realm != NULL && realm[0] != '\0') {
- rc = asprintf(&account,
- "%s$@%s",
- lp_netbios_name(),
- realm);
- if (rc < 0) {
- return false;
- }
- } else {
- rc = asprintf(&account,
- "%s$",
- lp_netbios_name());
- if (rc < 0) {
- return false;
- }
- }
+ cli_credentials_set_domain(auth_info->creds, lpcfg_workgroup(auth_info->lp_ctx),
+ CRED_SPECIFIED);
- pass = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
- if (!pass) {
+ status = cli_credentials_set_machine_account_db_ctx(auth_info->creds,
+ auth_info->lp_ctx,
+ db_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
d_printf("ERROR: Unable to fetch machine password for "
- "%s in domain %s\n",
- account, lp_workgroup());
- SAFE_FREE(account);
+ "%s in domain %s - %s\n",
+ lpcfg_netbios_name(auth_info->lp_ctx),
+ lpcfg_workgroup(auth_info->lp_ctx),
+ nt_errstr(status));
return false;
}
- set_cmdline_auth_info_username(auth_info, account);
- set_cmdline_auth_info_password(auth_info, pass);
+ return true;
+}
- SAFE_FREE(account);
- SAFE_FREE(pass);
+static const char *cmdline_auth_info_pw_callback(struct cli_credentials *creds)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ const char *name = NULL;
+ char *label = NULL;
+ char *ret = NULL;
+ char pwd[256] = {0};
+ int rc;
- return true;
+ name = cli_credentials_get_unparsed_name(creds, frame);
+ if (name == NULL) {
+ goto fail;
+ }
+ label = talloc_asprintf(frame, "Enter %s's password: ", name);
+ if (label == NULL) {
+ goto fail;
+ }
+ rc = samba_getpass(label, pwd, sizeof(pwd), false, false);
+ if (rc != 0) {
+ goto fail;
+ }
+ ret = talloc_strdup(creds, pwd);
+ if (ret == NULL) {
+ goto fail;
+ }
+ talloc_set_name_const(ret, __location__);
+fail:
+ ZERO_STRUCT(pwd);
+ TALLOC_FREE(frame);
+ return ret;
}
/****************************************************************************
@@ -322,11 +443,6 @@ bool set_cmdline_auth_info_machine_account_creds(struct user_auth_info *auth_inf
void set_cmdline_auth_info_getpass(struct user_auth_info *auth_info)
{
- char *label = NULL;
- char pwd[256] = {0};
- int rc;
- TALLOC_CTX *frame;
-
if (get_cmdline_auth_info_got_pass(auth_info) ||
get_cmdline_auth_info_use_ccache(auth_info) ||
get_cmdline_auth_info_use_kerberos(auth_info)) {
@@ -334,12 +450,12 @@ void set_cmdline_auth_info_getpass(struct user_auth_info *auth_info)
return;
}
- frame = talloc_stackframe();
- label = talloc_asprintf(frame, "Enter %s's password: ",
- get_cmdline_auth_info_username(auth_info));
- rc = samba_getpass(label, pwd, sizeof(pwd), false, false);
- if (rc == 0) {
- set_cmdline_auth_info_password(auth_info, pwd);
- }
- TALLOC_FREE(frame);
+ cli_credentials_set_password_callback(auth_info->creds,
+ cmdline_auth_info_pw_callback);
+}
+
+struct cli_credentials *get_cmdline_auth_info_creds(
+ const struct user_auth_info *auth_info)
+{
+ return auth_info->creds;
}
--
1.9.1
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20161216/ab34d2a4/signature.sig>
More information about the samba-technical
mailing list