1 # Unix SMB/CIFS implementation.
2 # Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 Tests auth logging tests that exercise SamLogon
24 from samba
.samdb
import SamDB
25 import samba
.tests
.auth_log_base
26 from samba
.credentials
import (
31 from samba
.dcerpc
import ntlmssp
, netlogon
32 from samba
.dcerpc
.dcerpc
import AS_SYSTEM_MAGIC_PATH_TOKEN
33 from samba
.ndr
import ndr_pack
34 from samba
.auth
import system_session
35 from samba
.tests
import delete_force
36 from samba
.dsdb
import UF_WORKSTATION_TRUST_ACCOUNT
, UF_PASSWD_NOTREQD
37 from samba
.dcerpc
.misc
import SEC_CHAN_WKSTA
38 from samba
.dcerpc
.windows_event_ids
import (
39 EVT_ID_SUCCESSFUL_LOGON
,
44 class AuthLogTestsSamLogon(samba
.tests
.auth_log_base
.AuthLogTestBase
):
48 self
.lp
= samba
.tests
.env_loadparm()
49 self
.session
= system_session()
51 session_info
=self
.session
,
54 self
.domain
= os
.environ
["DOMAIN"]
55 self
.netbios_name
= "SamLogonTest"
56 self
.machinepass
= "abcdefghij"
57 self
.remoteAddress
= AS_SYSTEM_MAGIC_PATH_TOKEN
58 self
.base_dn
= self
.ldb
.domain_dn()
59 self
.samlogon_dn
= ("cn=%s,cn=users,%s" %
60 (self
.netbios_name
, self
.base_dn
))
64 delete_force(self
.ldb
, self
.samlogon_dn
)
66 def _test_samlogon(self
, binding
, creds
, checkFunction
):
68 def isLastExpectedMessage(msg
):
70 msg
["type"] == "Authentication" and
71 msg
["Authentication"]["serviceDescription"] == "SamLogon" and
72 msg
["Authentication"]["authDescription"] == "network" and
73 msg
["Authentication"]["passwordType"] == "NTLMv2" and
74 (msg
["Authentication"]["eventId"] ==
75 EVT_ID_SUCCESSFUL_LOGON
) and
76 (msg
["Authentication"]["logonType"] == EVT_LOGON_NETWORK
))
79 binding
= "[schannel,%s]" % binding
81 binding
= "[schannel]"
83 utf16pw
= ('"' + self
.machinepass
+ '"').encode('utf-16-le')
85 "dn": self
.samlogon_dn
,
86 "objectclass": "computer",
87 "sAMAccountName": "%s$" % self
.netbios_name
,
89 str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD
),
90 "unicodePwd": utf16pw
})
92 machine_creds
= Credentials()
93 machine_creds
.guess(self
.get_loadparm())
94 machine_creds
.set_secure_channel_type(SEC_CHAN_WKSTA
)
95 machine_creds
.set_password(self
.machinepass
)
96 machine_creds
.set_username(self
.netbios_name
+ "$")
98 netlogon_conn
= netlogon
.netlogon("ncalrpc:%s" % binding
,
101 challenge
= b
"abcdefgh"
103 target_info
= ntlmssp
.AV_PAIR_LIST()
104 target_info
.count
= 3
106 domainname
= ntlmssp
.AV_PAIR()
107 domainname
.AvId
= ntlmssp
.MsvAvNbDomainName
108 domainname
.Value
= self
.domain
110 computername
= ntlmssp
.AV_PAIR()
111 computername
.AvId
= ntlmssp
.MsvAvNbComputerName
112 computername
.Value
= self
.netbios_name
114 eol
= ntlmssp
.AV_PAIR()
115 eol
.AvId
= ntlmssp
.MsvAvEOL
116 target_info
.pair
= [domainname
, computername
, eol
]
118 target_info_blob
= ndr_pack(target_info
)
120 response
= creds
.get_ntlm_response(flags
=CLI_CRED_NTLMv2_AUTH
,
122 target_info
=target_info_blob
)
126 logon_level
= netlogon
.NetlogonNetworkTransitiveInformation
127 logon
= samba
.dcerpc
.netlogon
.netr_NetworkInfo()
129 logon
.challenge
= list(challenge
)
130 logon
.nt
= netlogon
.netr_ChallengeResponse()
131 logon
.nt
.length
= len(response
["nt_response"])
132 logon
.nt
.data
= list(response
["nt_response"])
133 logon
.identity_info
= samba
.dcerpc
.netlogon
.netr_IdentityInfo()
134 (username
, domain
) = creds
.get_ntlm_username_domain()
136 logon
.identity_info
.domain_name
.string
= domain
137 logon
.identity_info
.account_name
.string
= username
138 logon
.identity_info
.workstation
.string
= creds
.get_workstation()
140 validation_level
= samba
.dcerpc
.netlogon
.NetlogonValidationSamInfo4
142 result
= netlogon_conn
.netr_LogonSamLogonEx(
143 os
.environ
["SERVER"],
144 machine_creds
.get_workstation(),
146 validation_level
, netr_flags
)
148 (validation
, authoritative
, netr_flags_out
) = result
150 messages
= self
.waitForMessages(isLastExpectedMessage
, netlogon_conn
)
151 checkFunction(messages
)
153 def samlogon_check(self
, messages
):
155 messages
= self
.remove_netlogon_messages(messages
)
156 expected_messages
= 5
157 self
.assertEqual(expected_messages
,
159 "Did not receive the expected number of messages")
161 # Check the first message it should be an Authorization
163 self
.assertEqual("Authorization", msg
["type"])
164 self
.assertEqual("DCE/RPC",
165 msg
["Authorization"]["serviceDescription"])
166 self
.assertEqual("ncalrpc", msg
["Authorization"]["authType"])
167 self
.assertEqual("NONE", msg
["Authorization"]["transportProtection"])
168 self
.assertTrue(self
.is_guid(msg
["Authorization"]["sessionId"]))
170 def test_ncalrpc_samlogon(self
):
172 creds
= self
.insta_creds(template
=self
.get_credentials(),
173 kerberos_state
=DONT_USE_KERBEROS
)
175 self
._test
_samlogon
("SEAL", creds
, self
.samlogon_check
)
176 except Exception as e
:
177 self
.fail("Unexpected exception: " + str(e
))