a0a2e2885f8123a41ded8aac12da06a92d2f6a3c
[amitay/samba.git] / python / samba / tests / auth_log_netlogon_bad_creds.py
1 # Unix SMB/CIFS implementation.
2 # Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
3 # Copyright (C) Catalyst IT Ltd. 2017
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 #
18
19 """
20     Tests that exercise auth logging for unsuccessful netlogon attempts.
21
22     NOTE: netlogon is only done once per session, so this file should only
23           test failed logons.  Adding a successful case will potentially break
24           the other tests, depending on the order of execution.
25 """
26
27 import samba.tests
28 import os
29 from samba import NTSTATUSError
30 from samba.samdb import SamDB
31 import samba.tests.auth_log_base
32 from samba.credentials import Credentials
33 from samba.dcerpc import netlogon
34 from samba.dcerpc.dcerpc import AS_SYSTEM_MAGIC_PATH_TOKEN
35 from samba.auth import system_session
36 from samba.tests import delete_force
37 from samba.dsdb import UF_WORKSTATION_TRUST_ACCOUNT, UF_PASSWD_NOTREQD
38 from samba.dcerpc.misc import SEC_CHAN_WKSTA
39 from samba.dcerpc.netlogon import NETLOGON_NEG_STRONG_KEYS
40
41
42 class AuthLogTestsNetLogonBadCreds(samba.tests.auth_log_base.AuthLogTestBase):
43
44     def setUp(self):
45         super(AuthLogTestsNetLogonBadCreds, self).setUp()
46         self.lp      = samba.tests.env_loadparm()
47         self.creds   = Credentials()
48
49         self.session = system_session()
50         self.ldb = SamDB(
51             session_info=self.session,
52             credentials=self.creds,
53             lp=self.lp)
54
55         self.domain        = os.environ["DOMAIN"]
56         self.netbios_name  = "NetLogonBad"
57         self.machinepass   = "abcdefghij"
58         self.remoteAddress = AS_SYSTEM_MAGIC_PATH_TOKEN
59         self.base_dn       = self.ldb.domain_dn()
60         self.dn            = ("cn=%s,cn=users,%s" %
61                               (self.netbios_name, self.base_dn))
62
63         utf16pw = unicode(
64             '"' + self.machinepass.encode('utf-8') + '"', 'utf-8'
65         ).encode('utf-16-le')
66         self.ldb.add({
67             "dn": self.dn,
68             "objectclass": "computer",
69             "sAMAccountName": "%s$" % self.netbios_name,
70             "userAccountControl":
71                 str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD),
72             "unicodePwd": utf16pw})
73
74     def tearDown(self):
75         super(AuthLogTestsNetLogonBadCreds, self).tearDown()
76         delete_force(self.ldb, self.dn)
77
78     def _test_netlogon(self, name, pwd, status, checkFunction):
79
80         def isLastExpectedMessage(msg):
81             return (
82                 msg["type"] == "Authentication" and
83                 msg["Authentication"]["serviceDescription"] == "NETLOGON" and
84                 msg["Authentication"]["authDescription"] ==
85                 "ServerAuthenticate" and
86                 msg["Authentication"]["status"] == status)
87
88         machine_creds = Credentials()
89         machine_creds.guess(self.get_loadparm())
90         machine_creds.set_secure_channel_type(SEC_CHAN_WKSTA)
91         machine_creds.set_password(pwd)
92         machine_creds.set_username(name + "$")
93
94         try:
95             netlogon.netlogon("ncalrpc:[schannel]",
96                               self.get_loadparm(),
97                               machine_creds)
98             self.fail("NTSTATUSError not raised")
99         except NTSTATUSError:
100             pass
101
102         messages = self.waitForMessages(isLastExpectedMessage)
103         checkFunction(messages)
104
105     def netlogon_check(self, messages):
106
107         expected_messages = 4
108         self.assertEquals(expected_messages,
109                           len(messages),
110                           "Did not receive the expected number of messages")
111
112         # Check the first message it should be an Authorization
113         msg = messages[0]
114         self.assertEquals("Authorization", msg["type"])
115         self.assertEquals("DCE/RPC",
116                           msg["Authorization"]["serviceDescription"])
117         self.assertEquals("ncalrpc", msg["Authorization"]["authType"])
118         self.assertEquals("NONE", msg["Authorization"]["transportProtection"])
119         self.assertTrue(self.is_guid(msg["Authorization"]["sessionId"]))
120
121     def test_netlogon_bad_machine_name(self):
122         self._test_netlogon("bad_name",
123                             self.machinepass,
124                             "NT_STATUS_NO_TRUST_SAM_ACCOUNT",
125                             self.netlogon_check)
126
127     def test_netlogon_bad_password(self):
128         self._test_netlogon(self.netbios_name,
129                             "badpass",
130                             "NT_STATUS_ACCESS_DENIED",
131                             self.netlogon_check)
132
133     def test_netlogon_password_DES(self):
134         """Logon failure that exercises the "DES" passwordType path.
135         """
136         def isLastExpectedMessage(msg):
137             return (
138                 msg["type"] == "Authentication" and
139                 msg["Authentication"]["serviceDescription"] == "NETLOGON" and
140                 msg["Authentication"]["authDescription"] ==
141                 "ServerAuthenticate" and
142                 msg["Authentication"]["passwordType"] == "DES")
143
144         c = netlogon.netlogon("ncalrpc:[schannel]", self.get_loadparm())
145         creds = netlogon.netr_Credential()
146         c.netr_ServerReqChallenge(self.server, self.netbios_name, creds)
147         try:
148             c.netr_ServerAuthenticate3(self.server,
149                                        self.netbios_name,
150                                        SEC_CHAN_WKSTA,
151                                        self.netbios_name,
152                                        creds,
153                                        0)
154         except NTSTATUSError:
155             pass
156         self.waitForMessages(isLastExpectedMessage)
157
158     def test_netlogon_password_HMAC_MD5(self):
159         """Logon failure that exercises the "HMAC-MD5" passwordType path.
160         """
161         def isLastExpectedMessage(msg):
162             return (
163                 msg["type"] == "Authentication" and
164                 msg["Authentication"]["serviceDescription"] == "NETLOGON" and
165                 msg["Authentication"]["authDescription"] ==
166                 "ServerAuthenticate" and
167                 msg["Authentication"]["passwordType"] == "HMAC-MD5")
168         c = netlogon.netlogon("ncalrpc:[schannel]", self.get_loadparm())
169         creds = netlogon.netr_Credential()
170         c.netr_ServerReqChallenge(self.server, self.netbios_name, creds)
171         try:
172             c.netr_ServerAuthenticate3(self.server,
173                                        self.netbios_name,
174                                        SEC_CHAN_WKSTA,
175                                        self.netbios_name,
176                                        creds,
177                                        NETLOGON_NEG_STRONG_KEYS)
178         except NTSTATUSError:
179             pass
180         self.waitForMessages(isLastExpectedMessage)