--- /dev/null
+# Unix SMB/CIFS implementation.
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
+# Copyright (C) Catalyst IT Ltd. 2017
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+"""
+ Tests that exercise the auth logging for a successful netlogon attempt
+
+ NOTE: As the netlogon authentication is performed once per session,
+ there is only one test in this routine. If another test is added
+ only the test executed first will generate the netlogon auth message
+"""
+
+import samba.tests
+import os
+from samba.samdb import SamDB
+import samba.tests.auth_log_base
+from samba.credentials import Credentials
+from samba.dcerpc import netlogon
+from samba.dcerpc.dcerpc import AS_SYSTEM_MAGIC_PATH_TOKEN
+from samba.auth import system_session
+from samba.tests import delete_force
+from samba.dsdb import UF_WORKSTATION_TRUST_ACCOUNT, UF_PASSWD_NOTREQD
+from samba.dcerpc.misc import SEC_CHAN_WKSTA
+
+
+class AuthLogTestsNetLogon(samba.tests.auth_log_base.AuthLogTestBase):
+
+ def setUp(self):
+ super(AuthLogTestsNetLogon, self).setUp()
+ self.lp = samba.tests.env_loadparm()
+ self.creds = Credentials()
+
+ self.session = system_session()
+ self.ldb = SamDB(
+ session_info=self.session,
+ credentials=self.creds,
+ lp=self.lp)
+
+ self.domain = os.environ["DOMAIN"]
+ self.netbios_name = "NetLogonGood"
+ self.machinepass = "abcdefghij"
+ self.remoteAddress = AS_SYSTEM_MAGIC_PATH_TOKEN
+ self.base_dn = self.ldb.domain_dn()
+ self.dn = ("cn=%s,cn=users,%s" %
+ (self.netbios_name, self.base_dn))
+
+ utf16pw = unicode(
+ '"' + self.machinepass.encode('utf-8') + '"', 'utf-8'
+ ).encode('utf-16-le')
+ self.ldb.add({
+ "dn": self.dn,
+ "objectclass": "computer",
+ "sAMAccountName": "%s$" % self.netbios_name,
+ "userAccountControl":
+ str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD),
+ "unicodePwd": utf16pw})
+
+ def tearDown(self):
+ super(AuthLogTestsNetLogon, self).tearDown()
+ delete_force(self.ldb, self.dn)
+
+ def _test_netlogon(self, binding, checkFunction):
+
+ def isLastExpectedMessage(msg):
+ return (
+ msg["type"] == "Authorization" and
+ msg["Authorization"]["serviceDescription"] == "DCE/RPC" and
+ msg["Authorization"]["authType"] == "schannel" and
+ msg["Authorization"]["transportProtection"] == "SEAL")
+
+ if binding:
+ binding = "[schannel,%s]" % binding
+ else:
+ binding = "[schannel]"
+
+ machine_creds = Credentials()
+ machine_creds.guess(self.get_loadparm())
+ machine_creds.set_secure_channel_type(SEC_CHAN_WKSTA)
+ machine_creds.set_password(self.machinepass)
+ machine_creds.set_username(self.netbios_name + "$")
+
+ netlogon_conn = netlogon.netlogon("ncalrpc:%s" % binding,
+ self.get_loadparm(),
+ machine_creds)
+
+ messages = self.waitForMessages(isLastExpectedMessage, netlogon_conn)
+ checkFunction(messages)
+
+ def netlogon_check(self, messages):
+
+ expected_messages = 5
+ self.assertEquals(expected_messages,
+ len(messages),
+ "Did not receive the expected number of messages")
+
+ # Check the first message it should be an Authorization
+ msg = messages[0]
+ self.assertEquals("Authorization", msg["type"])
+ self.assertEquals("DCE/RPC",
+ msg["Authorization"]["serviceDescription"])
+ self.assertEquals("ncalrpc", msg["Authorization"]["authType"])
+ self.assertEquals("NONE", msg["Authorization"]["transportProtection"])
+
+ # Check the fourth message it should be a NETLOGON Authentication
+ msg = messages[3]
+ self.assertEquals("Authentication", msg["type"])
+ self.assertEquals("NETLOGON",
+ msg["Authentication"]["serviceDescription"])
+ self.assertEquals("ServerAuthenticate",
+ msg["Authentication"]["authDescription"])
+ self.assertEquals("NT_STATUS_OK",
+ msg["Authentication"]["status"])
+ self.assertEquals("HMAC-SHA256",
+ msg["Authentication"]["passwordType"])
+
+ def test_netlogon(self):
+ self._test_netlogon("SEAL", self.netlogon_check)
--- /dev/null
+# Unix SMB/CIFS implementation.
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
+# Copyright (C) Catalyst IT Ltd. 2017
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+"""
+ Tests that exercise auth logging for unsuccessful netlogon attempts.
+
+ NOTE: netlogon is only done once per session, so this file should only
+ test failed logons. Adding a successful case will potentially break
+ the other tests, depending on the order of execution.
+"""
+
+import samba.tests
+import os
+from samba import NTSTATUSError
+from samba.samdb import SamDB
+import samba.tests.auth_log_base
+from samba.credentials import Credentials
+from samba.dcerpc import netlogon
+from samba.dcerpc.dcerpc import AS_SYSTEM_MAGIC_PATH_TOKEN
+from samba.auth import system_session
+from samba.tests import delete_force
+from samba.dsdb import UF_WORKSTATION_TRUST_ACCOUNT, UF_PASSWD_NOTREQD
+from samba.dcerpc.misc import SEC_CHAN_WKSTA
+
+
+class AuthLogTestsNetLogonBadCreds(samba.tests.auth_log_base.AuthLogTestBase):
+
+ def setUp(self):
+ super(AuthLogTestsNetLogonBadCreds, self).setUp()
+ self.lp = samba.tests.env_loadparm()
+ self.creds = Credentials()
+
+ self.session = system_session()
+ self.ldb = SamDB(
+ session_info=self.session,
+ credentials=self.creds,
+ lp=self.lp)
+
+ self.domain = os.environ["DOMAIN"]
+ self.netbios_name = "NetLogonBad"
+ self.machinepass = "abcdefghij"
+ self.remoteAddress = AS_SYSTEM_MAGIC_PATH_TOKEN
+ self.base_dn = self.ldb.domain_dn()
+ self.dn = ("cn=%s,cn=users,%s" %
+ (self.netbios_name, self.base_dn))
+
+ utf16pw = unicode(
+ '"' + self.machinepass.encode('utf-8') + '"', 'utf-8'
+ ).encode('utf-16-le')
+ self.ldb.add({
+ "dn": self.dn,
+ "objectclass": "computer",
+ "sAMAccountName": "%s$" % self.netbios_name,
+ "userAccountControl":
+ str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD),
+ "unicodePwd": utf16pw})
+
+ def tearDown(self):
+ super(AuthLogTestsNetLogonBadCreds, self).tearDown()
+ delete_force(self.ldb, self.dn)
+
+ def _test_netlogon(self, name, pwd, status, checkFunction):
+
+ def isLastExpectedMessage(msg):
+ return (
+ msg["type"] == "Authentication" and
+ msg["Authentication"]["serviceDescription"] == "NETLOGON" and
+ msg["Authentication"]["authDescription"] ==
+ "ServerAuthenticate" and
+ msg["Authentication"]["status"] == status)
+
+ machine_creds = Credentials()
+ machine_creds.guess(self.get_loadparm())
+ machine_creds.set_secure_channel_type(SEC_CHAN_WKSTA)
+ machine_creds.set_password(pwd)
+ machine_creds.set_username(name + "$")
+
+ try:
+ netlogon.netlogon("ncalrpc:[schannel]",
+ self.get_loadparm(),
+ machine_creds)
+ self.fail("NTSTATUSError not raised")
+ except NTSTATUSError:
+ pass
+
+ messages = self.waitForMessages(isLastExpectedMessage)
+ checkFunction(messages)
+
+ def netlogon_check(self, messages):
+
+ expected_messages = 4
+ self.assertEquals(expected_messages,
+ len(messages),
+ "Did not receive the expected number of messages")
+
+ # Check the first message it should be an Authorization
+ msg = messages[0]
+ self.assertEquals("Authorization", msg["type"])
+ self.assertEquals("DCE/RPC",
+ msg["Authorization"]["serviceDescription"])
+ self.assertEquals("ncalrpc", msg["Authorization"]["authType"])
+ self.assertEquals("NONE", msg["Authorization"]["transportProtection"])
+
+ def test_netlogon_bad_machine_name(self):
+ self._test_netlogon("bad_name",
+ self.machinepass,
+ "NT_STATUS_NO_TRUST_SAM_ACCOUNT",
+ self.netlogon_check)
+
+ def test_netlogon_bad_password(self):
+ self._test_netlogon(self.netbios_name,
+ "badpass",
+ "NT_STATUS_ACCESS_DENIED",
+ self.netlogon_check)
+
+ def test_netlogon_password_DES(self):
+ """Logon failure that exercises the "DES" passwordType path.
+ """
+ def isLastExpectedMessage(msg):
+ return (
+ msg["type"] == "Authentication" and
+ msg["Authentication"]["serviceDescription"] == "NETLOGON" and
+ msg["Authentication"]["authDescription"] ==
+ "ServerAuthenticate" and
+ msg["Authentication"]["passwordType"] == "DES")
+
+ c = netlogon.netlogon("ncalrpc:[schannel]", self.get_loadparm())
+ creds = netlogon.netr_Credential()
+ c.netr_ServerReqChallenge(self.server, self.netbios_name, creds)
+ try:
+ c.netr_ServerAuthenticate3(self.server,
+ self.netbios_name,
+ SEC_CHAN_WKSTA,
+ self.netbios_name,
+ creds,
+ 0)
+ except NTSTATUSError:
+ pass
+ self.waitForMessages(isLastExpectedMessage)
+
+ def test_netlogon_password_HMAC_MD5(self):
+ """Logon failure that exercises the "HMAC-MD5" passwordType path.
+ """
+ def isLastExpectedMessage(msg):
+ return (
+ msg["type"] == "Authentication" and
+ msg["Authentication"]["serviceDescription"] == "NETLOGON" and
+ msg["Authentication"]["authDescription"] ==
+ "ServerAuthenticate" and
+ msg["Authentication"]["passwordType"] == "HMAC-MD5")
+ c = netlogon.netlogon("ncalrpc:[schannel]", self.get_loadparm())
+ creds = netlogon.netr_Credential()
+ c.netr_ServerReqChallenge(self.server, self.netbios_name, creds)
+ try:
+ c.netr_ServerAuthenticate3(self.server,
+ self.netbios_name,
+ SEC_CHAN_WKSTA,
+ self.netbios_name,
+ creds,
+ 0x00004000)
+ except NTSTATUSError:
+ pass
+ self.waitForMessages(isLastExpectedMessage)
--- /dev/null
+# NETLOGON authentication logging tests, currently fail as the
+# code has not been implemented
+^samba.tests.auth_log_netlogon_bad_creds.samba.tests.auth_log_netlogon_bad_creds.AuthLogTestsNetLogonBadCreds.test_netlogon_bad_password\(ad_dc_ntvfs:local\)
+^samba.tests.auth_log_netlogon_bad_creds.samba.tests.auth_log_netlogon_bad_creds.AuthLogTestsNetLogonBadCreds.test_netlogon_bad_machine_name\(ad_dc_ntvfs:local\)
+^samba.tests.auth_log_netlogon_bad_creds.samba.tests.auth_log_netlogon_bad_creds.AuthLogTestsNetLogonBadCreds.test_netlogon_bad_password\(ad_dc:local\)
+^samba.tests.auth_log_netlogon_bad_creds.samba.tests.auth_log_netlogon_bad_creds.AuthLogTestsNetLogonBadCreds.test_netlogon_bad_machine_name\(ad_dc:local\)
+^samba.tests.auth_log_netlogon.samba.tests.auth_log_netlogon.AuthLogTestsNetLogon.test_netlogon\(ad_dc_ntvfs:local\)
+^samba.tests.auth_log_netlogon.samba.tests.auth_log_netlogon.AuthLogTestsNetLogon.test_netlogon\(ad_dc:local\)
extra_args=['-U"$USERNAME%$PASSWORD"'],
environ={'CLIENT_IP': '127.0.0.11',
'SOCKET_WRAPPER_DEFAULT_IFACE': 11})
+ planoldpythontestsuite("ad_dc:local", "samba.tests.auth_log_netlogon",
+ extra_args=['-U"$USERNAME%$PASSWORD"'],
+ environ={'CLIENT_IP': '127.0.0.11',
+ 'SOCKET_WRAPPER_DEFAULT_IFACE': 11})
+ planoldpythontestsuite("ad_dc_ntvfs:local", "samba.tests.auth_log_netlogon",
+ extra_args=['-U"$USERNAME%$PASSWORD"'],
+ environ={'CLIENT_IP': '127.0.0.11',
+ 'SOCKET_WRAPPER_DEFAULT_IFACE': 11})
+ planoldpythontestsuite("ad_dc:local",
+ "samba.tests.auth_log_netlogon_bad_creds",
+ extra_args=['-U"$USERNAME%$PASSWORD"'],
+ environ={'CLIENT_IP': '127.0.0.11',
+ 'SOCKET_WRAPPER_DEFAULT_IFACE': 11})
+ planoldpythontestsuite("ad_dc_ntvfs:local",
+ "samba.tests.auth_log_netlogon_bad_creds",
+ extra_args=['-U"$USERNAME%$PASSWORD"'],
+ environ={'CLIENT_IP': '127.0.0.11',
+ 'SOCKET_WRAPPER_DEFAULT_IFACE': 11})
planoldpythontestsuite("ad_dc",
"samba.tests.net_join_no_spnego",
extra_args=['-U"$USERNAME%$PASSWORD"'])