1# Dispatch for various request types.
2#
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#
18import os
19import ctypes
20import random
21
22from samba.net import Net
23from samba.dcerpc import security, drsuapi, nbt, lsa, netlogon, ntlmssp
24from samba.dcerpc.netlogon import netr_WorkstationInformation
25from samba.dcerpc.security import dom_sid
26from samba.netbios import Node
27from samba.ndr import ndr_pack
28from samba.credentials import (
29    CLI_CRED_NTLMv2_AUTH,
30    MUST_USE_KERBEROS,
31    DONT_USE_KERBEROS
32)
33from samba import NTSTATUSError
34from samba.ntstatus import (
35    NT_STATUS_OBJECT_NAME_NOT_FOUND,
36    NT_STATUS_NO_SUCH_DOMAIN
37)
38import samba
39import dns.resolver
40from ldb import SCOPE_BASE
41
42def uint32(v):
43    return ctypes.c_uint32(v).value
44
45
46def check_runtime_error(runtime, val):
47    if runtime is None:
48        return False
49
50    err32 = uint32(runtime.args[0])
51    if err32 == val:
52        return True
53
54    return False
55
56
57name_formats = [
58    drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
59    drsuapi.DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
60    drsuapi.DRSUAPI_DS_NAME_FORMAT_DISPLAY,
61    drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID,
62    drsuapi.DRSUAPI_DS_NAME_FORMAT_CANONICAL,
63    drsuapi.DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
64    drsuapi.DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
65    drsuapi.DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
66    drsuapi.DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
67    drsuapi.DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN,
68    drsuapi.DRSUAPI_DS_NAME_FORMAT_UPN_AND_ALTSECID,
69    drsuapi.DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT_NAME_SANS_DOMAIN_EX,
70    drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_GLOBAL_CATALOG_SERVERS,
71    drsuapi.DRSUAPI_DS_NAME_FORMAT_UPN_FOR_LOGON,
72    drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_SERVERS_WITH_DCS_IN_SITE,
73    drsuapi.DRSUAPI_DS_NAME_FORMAT_STRING_SID_NAME,
74    drsuapi.DRSUAPI_DS_NAME_FORMAT_ALT_SECURITY_IDENTITIES_NAME,
75    drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_NCS,
76    drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_DOMAINS,
77    drsuapi.DRSUAPI_DS_NAME_FORMAT_MAP_SCHEMA_GUID,
78    drsuapi.DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT_NAME_SANS_DOMAIN,
79    drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_ROLES,
80    drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_INFO_FOR_SERVER,
81    drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_SERVERS_FOR_DOMAIN_IN_SITE,
82    drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_DOMAINS_IN_SITE,
83    drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_SERVERS_IN_SITE,
84    drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_SITES,
85]
86
87
88def warning(message):
89    print("\033[37;41;1m" "Warning: %s" "\033[00m" % (message))
90
91###############################################################################
92#
93# Packet generation functions:
94#
95# All the packet generation functions have the following form:
96#  packet_${protocol}_${opcode}(packet, conversation, context)
97#
98#  The functions return true, if statistics should be collected for the packet
99#                      false, the packet has been ignored.
100#
101# Where:
102#   protocol is the protocol, i.e. cldap, dcerpc, ...
103#   opcode   is the protocol op code i.e. type of the packet to be
104#            generated.
105#
106#   packet contains data about the captured/generated packet
107#          provides any extra data needed to generate the packet
108#
109#   conversation Details of the current client/server interaction
110#
111#   context state data for the current interaction
112#
113#
114#
115# The following protocols are not currently handled:
116#     smb
117#     smb2
118#     browser
119#     smb_netlogon
120#
121# The following drsuapi replication packets are currently ignored:
122#     DsReplicaSync
123#     DsGetNCChanges
124#     DsReplicaUpdateRefs
125
126
127# Packet generators that do NOTHING are assigned to the null_packet
128# function which allows the conversation generators to notice this and
129# avoid a whole lot of pointless work.
130def null_packet(packet, conversation, context):
131    return False
132
133
134def packet_cldap_3(packet, conversation, context):
135    # searchRequest
136    net = Net(creds=context.creds, lp=context.lp)
137    net.finddc(domain=context.lp.get('realm'),
138               flags=(nbt.NBT_SERVER_LDAP |
139                      nbt.NBT_SERVER_DS |
140                      nbt.NBT_SERVER_WRITABLE))
141    return True
142
143
144packet_cldap_5 = null_packet
145# searchResDone
146
147packet_dcerpc_0  = null_packet
148# Request
149# Can be ignored, it's the continuation of an existing conversation
150
151packet_dcerpc_2 = null_packet
152# Request
153# Server response, so should be ignored
154
155packet_dcerpc_3 = null_packet
156
157packet_dcerpc_11 = null_packet
158# Bind
159# creation of the rpc dcerpc connection is managed by the higher level
160# protocol drivers. So we ignore it when generating traffic
161
162
163packet_dcerpc_12 = null_packet
164# Bind_ack
165# Server response, so should be ignored
166
167
168packet_dcerpc_13 = null_packet
169# Bind_nak
170# Server response, so should be ignored
171
172
173packet_dcerpc_14 = null_packet
174# Alter_context
175# Generated as part of the connect process
176
177
178def packet_dcerpc_15(packet, conversation, context):
179    # Alter_context_resp
180    # This means it was GSSAPI/krb5 (probably)
181    # Check the kerberos_state and issue a diagnostic if kerberos not enabled
182    if context.user_creds.get_kerberos_state() == DONT_USE_KERBEROS:
183        warning("Kerberos disabled but have dcerpc Alter_context_resp "
184                "indicating Kerberos was used")
185    return False
186
187
188def packet_dcerpc_16(packet, conversation, context):
189    # AUTH3
190    # This means it was NTLMSSP
191    # Check the kerberos_state and issue a diagnostic if kerberos enabled
192    if context.user_creds.get_kerberos_state() == MUST_USE_KERBEROS:
193        warning("Kerberos enabled but have dcerpc AUTH3 "
194                "indicating NTLMSSP was used")
195    return False
196
197
198def packet_dns_0(packet, conversation, context):
199    # query
200    name, rtype = context.guess_a_dns_lookup()
201    dns.resolver.query(name, rtype)
202    return True
203
204
205packet_dns_1 = null_packet
206# response
207# Server response, so should be ignored
208
209
210def packet_drsuapi_0(packet, conversation, context):
211    # DsBind
212    context.get_drsuapi_connection_pair(True)
213    return True
214
215
216NAME_FORMATS = [getattr(drsuapi, _x) for _x in dir(drsuapi)
217                if 'NAME_FORMAT' in _x]
218
219
220def packet_drsuapi_12(packet, conversation, context):
221    # DsCrackNames
222    drs, handle = context.get_drsuapi_connection_pair()
223
224    names = drsuapi.DsNameString()
225    names.str = context.server
226
227    req = drsuapi.DsNameRequest1()
228    req.format_flags = 0
229    req.format_offered = 7
230    req.format_desired = random.choice(name_formats)
231    req.codepage = 1252
232    req.language = 1033  # German, I think
233    req.format_flags = 0
234    req.count = 1
235    req.names = [names]
236
237    (result, ctr) = drs.DsCrackNames(handle, 1, req)
238    return True
239
240
241def packet_drsuapi_13(packet, conversation, context):
242    # DsWriteAccountSpn
243    req = drsuapi.DsWriteAccountSpnRequest1()
244    req.operation = drsuapi.DRSUAPI_DS_SPN_OPERATION_REPLACE
245    req.unknown1 = 0  # Unused, must be 0
246    req.object_dn = context.user_dn
247    req.count = 1  # only 1 name
248    spn_name = drsuapi.DsNameString()
249    spn_name.str = 'foo/{}'.format(context.username)
250    req.spn_names = [spn_name]
251    (drs, handle) = context.get_drsuapi_connection_pair()
252    (level, res) = drs.DsWriteAccountSpn(handle, 1, req)
253    return True
254
255
256def packet_drsuapi_1(packet, conversation, context):
257    # DsUnbind
258    (drs, handle) = context.get_drsuapi_connection_pair()
259    drs.DsUnbind(handle)
260    del context.drsuapi_connections[-1]
261    return True
262
263
264packet_drsuapi_2 = null_packet
265# DsReplicaSync
266# This is between DCs, triggered on a DB change
267# Ignoring for now
268
269
270packet_drsuapi_3 = null_packet
271# DsGetNCChanges
272# This is between DCs, trigger with DB operation,
273# or DsReplicaSync between DCs.
274# Ignoring for now
275
276
277packet_drsuapi_4 = null_packet
278# DsReplicaUpdateRefs
279# Ignoring for now
280
281
282packet_epm_3 = null_packet
283# Map
284# Will be generated by higher level protocol calls
285
286
287def packet_kerberos_(packet, conversation, context):
288    # Use the presence of kerberos packets as a hint to enable kerberos
289    # for the rest of the conversation.
290    # i.e. kerberos packets are not explicitly generated.
291    context.user_creds.set_kerberos_state(MUST_USE_KERBEROS)
292    context.user_creds_bad.set_kerberos_state(MUST_USE_KERBEROS)
293    context.machine_creds.set_kerberos_state(MUST_USE_KERBEROS)
294    context.machine_creds_bad.set_kerberos_state(MUST_USE_KERBEROS)
295    context.creds.set_kerberos_state(MUST_USE_KERBEROS)
296    return False
297
298
299packet_ldap_ = null_packet
300# Unknown
301# The ldap payload was probably encrypted so just ignore it.
302
303
304def packet_ldap_0(packet, conversation, context):
305    # bindRequest
306    if packet.extra[5] == "simple":
307        # Perform a simple bind.
308        context.get_ldap_connection(new=True, simple=True)
309    else:
310        # Perform a sasl bind.
311        context.get_ldap_connection(new=True, simple=False)
312    return True
313
314
315packet_ldap_1 = null_packet
316# bindResponse
317# Server response ignored for traffic generation
318
319
320def packet_ldap_2(packet, conversation, context):
321    # unbindRequest
322    # pop the last one off -- most likely we're in a bind/unbind ping.
323    del context.ldap_connections[-1:]
324    return False
325
326
327def packet_ldap_3(packet, conversation, context):
328    # searchRequest
329
330    (scope, dn_sig, filter, attrs, extra, desc, oid) = packet.extra
331    if not scope:
332        scope = SCOPE_BASE
333
334    samdb = context.get_ldap_connection()
335    dn = context.get_matching_dn(dn_sig)
336
337    # try to guess the search expression (don't bother for base searches, as
338    # they're only looking up a single object)
339    if (filter is None or filter is '') and scope != SCOPE_BASE:
340        filter = context.guess_search_filter(attrs, dn_sig, dn)
341
342    samdb.search(dn,
343                 expression=filter,
344                 scope=int(scope),
345                 attrs=attrs.split(','),
346                 controls=["paged_results:1:1000"])
347    return True
348
349
350packet_ldap_4 = null_packet
351# searchResEntry
352# Server response ignored for traffic generation
353
354
355packet_ldap_5 = null_packet
356# Server response ignored for traffic generation
357
358packet_ldap_6 = null_packet
359
360packet_ldap_7 = null_packet
361
362packet_ldap_8 = null_packet
363
364packet_ldap_9 = null_packet
365
366packet_ldap_16 = null_packet
367
368packet_lsarpc_0 = null_packet
369# lsarClose
370
371packet_lsarpc_1 = null_packet
372# lsarDelete
373
374packet_lsarpc_2 = null_packet
375# lsarEnumeratePrivileges
376
377packet_lsarpc_3 = null_packet
378# LsarQuerySecurityObject
379
380packet_lsarpc_4 = null_packet
381# LsarSetSecurityObject
382
383packet_lsarpc_5 = null_packet
384# LsarChangePassword
385
386packet_lsarpc_6 = null_packet
387# lsa_OpenPolicy
388# We ignore this, but take it as a hint that the lsarpc handle should
389# be over a named pipe.
390#
391
392
393def packet_lsarpc_14(packet, conversation, context):
394    # lsa_LookupNames
395    c = context.get_lsarpc_named_pipe_connection()
396
397    objectAttr = lsa.ObjectAttribute()
398    pol_handle = c.OpenPolicy2(u'', objectAttr,
399                               security.SEC_FLAG_MAXIMUM_ALLOWED)
400
401    sids  = lsa.TransSidArray()
402    names = [lsa.String("This Organization"),
403             lsa.String("Digest Authentication")]
404    level = lsa.LSA_LOOKUP_NAMES_ALL
405    count = 0
406    c.LookupNames(pol_handle, names, sids, level, count)
407    return True
408
409
410def packet_lsarpc_15(packet, conversation, context):
411    # lsa_LookupSids
412    c = context.get_lsarpc_named_pipe_connection()
413
414    objectAttr = lsa.ObjectAttribute()
415    pol_handle = c.OpenPolicy2(u'', objectAttr,
416                               security.SEC_FLAG_MAXIMUM_ALLOWED)
417
418    sids = lsa.SidArray()
419    sid = lsa.SidPtr()
420
421    x = dom_sid("S-1-5-7")
422    sid.sid = x
423    sids.sids = [sid]
424    sids.num_sids = 1
425    names = lsa.TransNameArray()
426    level = lsa.LSA_LOOKUP_NAMES_ALL
427    count = 0
428
429    c.LookupSids(pol_handle, sids, names, level, count)
430    return True
431
432
433def packet_lsarpc_39(packet, conversation, context):
434    # lsa_QueryTrustedDomainInfoBySid
435    # Samba does not support trusted domains, so this call is expected to fail
436    #
437    c = context.get_lsarpc_named_pipe_connection()
438
439    objectAttr = lsa.ObjectAttribute()
440
441    pol_handle = c.OpenPolicy2(u'', objectAttr,
442                               security.SEC_FLAG_MAXIMUM_ALLOWED)
443
444    domsid = security.dom_sid(context.domain_sid)
445    level = 1
446    try:
447        c.QueryTrustedDomainInfoBySid(pol_handle, domsid, level)
448    except NTSTATUSError as error:
449        # Object Not found is the expected result from samba,
450        # while No Such Domain is the expected result from windows,
451        # anything else is a failure.
452        if not check_runtime_error(error, NT_STATUS_OBJECT_NAME_NOT_FOUND) \
453                and not check_runtime_error(error, NT_STATUS_NO_SUCH_DOMAIN):
454            raise
455    return True
456
457
458packet_lsarpc_40 = null_packet
459# lsa_SetTrustedDomainInfo
460# Not currently supported
461
462
463packet_lsarpc_43 = null_packet
464# LsaStorePrivateData
465
466
467packet_lsarpc_44 = null_packet
468# LsaRetrievePrivateData
469
470
471packet_lsarpc_68 = null_packet
472# LsarLookupNames3
473
474
475def packet_lsarpc_76(packet, conversation, context):
476    # lsa_LookupSids3
477    c = context.get_lsarpc_connection()
478    sids = lsa.SidArray()
479    sid = lsa.SidPtr()
480    # Need a set
481    x = dom_sid("S-1-5-7")
482    sid.sid = x
483    sids.sids = [sid]
484    sids.num_sids = 1
485    names = lsa.TransNameArray2()
486    level = lsa.LSA_LOOKUP_NAMES_ALL
487    count = 0
488    lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES
489    client_revision = lsa.LSA_CLIENT_REVISION_2
490    c.LookupSids3(sids, names, level, count, lookup_options, client_revision)
491    return True
492
493
494def packet_lsarpc_77(packet, conversation, context):
495    # lsa_LookupNames4
496    c = context.get_lsarpc_connection()
497    sids  = lsa.TransSidArray3()
498    names = [lsa.String("This Organization"),
499             lsa.String("Digest Authentication")]
500    level = lsa.LSA_LOOKUP_NAMES_ALL
501    count = 0
502    lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES
503    client_revision = lsa.LSA_CLIENT_REVISION_2
504    c.LookupNames4(names, sids, level, count, lookup_options, client_revision)
505    return True
506
507
508def packet_nbns_0(packet, conversation, context):
509    # query
510    n = Node()
511    try:
512        n.query_name("ANAME", context.server, timeout=4, broadcast=False)
513    except:
514        pass
515    return True
516
517
518packet_nbns_1 = null_packet
519# response
520# Server response, not generated by the client
521
522
523packet_rpc_netlogon_0 = null_packet
524
525packet_rpc_netlogon_1 = null_packet
526
527packet_rpc_netlogon_4 = null_packet
528# NetrServerReqChallenge
529# generated by higher level protocol drivers
530# ignored for traffic generation
531
532packet_rpc_netlogon_14 = null_packet
533
534packet_rpc_netlogon_15 = null_packet
535
536packet_rpc_netlogon_21 = null_packet
537# NetrLogonDummyRoutine1
538# Used to determine security settings. Triggered from schannel setup
539# So no need for an explicit generator
540
541
542packet_rpc_netlogon_26 = null_packet
543# NetrServerAuthenticate3
544# Triggered from schannel set up, no need for an explicit generator
545
546
547def packet_rpc_netlogon_29(packet, conversation, context):
548    # NetrLogonGetDomainInfo [531]
549    c = context.get_netlogon_connection()
550    (auth, succ) = context.get_authenticator()
551    query = netr_WorkstationInformation()
552
553    c.netr_LogonGetDomainInfo(context.server,
554                              context.netbios_name,
555                              auth,
556                              succ,
557                              2,      # TODO are there other values?
558                              query)
559    return True
560
561
562def packet_rpc_netlogon_30(packet, conversation, context):
563    # NetrServerPasswordSet2
564    c = context.get_netlogon_connection()
565    (auth, succ) = context.get_authenticator()
566    DATA_LEN = 512
567    # Set the new password to the existing password, this generates the same
568    # work load as a new value, and leaves the account password intact for
569    # subsequent runs
570    newpass = context.machine_creds.get_password().encode('utf-16-le')
571    pwd_len = len(newpass)
572    filler  = [x if isinstance(x, int) else ord(x) for x in os.urandom(DATA_LEN - pwd_len)]
573    pwd = netlogon.netr_CryptPassword()
574    pwd.length = pwd_len
575    pwd.data = filler + [x if isinstance(x, int) else ord(x) for x in newpass]
576    context.machine_creds.encrypt_netr_crypt_password(pwd)
577    c.netr_ServerPasswordSet2(context.server,
578                              # must ends with $, so use get_username instead
579                              # of get_workstation here
580                              context.machine_creds.get_username(),
581                              context.machine_creds.get_secure_channel_type(),
582                              context.netbios_name,
583                              auth,
584                              pwd)
585    return True
586
587
588packet_rpc_netlogon_34 = null_packet
589
590
591def packet_rpc_netlogon_39(packet, conversation, context):
592    # NetrLogonSamLogonEx [4331]
593    def connect(creds):
594        c = context.get_netlogon_connection()
595
596        # Disable Kerberos in cli creds to extract NTLM response
597        old_state = creds.get_kerberos_state()
598        creds.set_kerberos_state(DONT_USE_KERBEROS)
599
600        logon = samlogon_logon_info(context.domain,
601                                    context.netbios_name,
602                                    creds)
603        logon_level = netlogon.NetlogonNetworkTransitiveInformation
604        validation_level = netlogon.NetlogonValidationSamInfo4
605        netr_flags = 0
606        c.netr_LogonSamLogonEx(context.server,
607                               context.machine_creds.get_workstation(),
608                               logon_level,
609                               logon,
610                               validation_level,
611                               netr_flags)
612
613        creds.set_kerberos_state(old_state)
614
615    context.last_samlogon_bad =\
616        context.with_random_bad_credentials(connect,
617                                            context.user_creds,
618                                            context.user_creds_bad,
619                                            context.last_samlogon_bad)
620    return True
621
622
623def samlogon_target(domain_name, computer_name):
624    target_info = ntlmssp.AV_PAIR_LIST()
625    target_info.count = 3
626    computername = ntlmssp.AV_PAIR()
627    computername.AvId = ntlmssp.MsvAvNbComputerName
628    computername.Value = computer_name
629
630    domainname = ntlmssp.AV_PAIR()
631    domainname.AvId = ntlmssp.MsvAvNbDomainName
632    domainname.Value = domain_name
633
634    eol = ntlmssp.AV_PAIR()
635    eol.AvId = ntlmssp.MsvAvEOL
636    target_info.pair = [domainname, computername, eol]
637
638    return ndr_pack(target_info)
639
640
641def samlogon_logon_info(domain_name, computer_name, creds):
642
643    target_info_blob = samlogon_target(domain_name, computer_name)
644
645    challenge = b"abcdefgh"
646    # User account under test
647    response = creds.get_ntlm_response(flags=CLI_CRED_NTLMv2_AUTH,
648                                       challenge=challenge,
649                                       target_info=target_info_blob)
650
651    logon = netlogon.netr_NetworkInfo()
652
653    logon.challenge     = [x if isinstance(x, int) else ord(x) for x in challenge]
654    logon.nt            = netlogon.netr_ChallengeResponse()
655    logon.nt.length     = len(response["nt_response"])
656    logon.nt.data       = [x if isinstance(x, int) else ord(x) for x in response["nt_response"]]
657
658    logon.identity_info = netlogon.netr_IdentityInfo()
659
660    (username, domain)  = creds.get_ntlm_username_domain()
661    logon.identity_info.domain_name.string  = domain
662    logon.identity_info.account_name.string = username
663    logon.identity_info.workstation.string  = creds.get_workstation()
664
665    return logon
666
667
668def packet_rpc_netlogon_40(packet, conversation, context):
669    # DsrEnumerateDomainTrusts
670    c = context.get_netlogon_connection()
671    c.netr_DsrEnumerateDomainTrusts(
672        context.server,
673        netlogon.NETR_TRUST_FLAG_IN_FOREST |
674        netlogon.NETR_TRUST_FLAG_OUTBOUND  |
675        netlogon.NETR_TRUST_FLAG_INBOUND)
676    return True
677
678
679def packet_rpc_netlogon_45(packet, conversation, context):
680    # NetrLogonSamLogonWithFlags [7]
681    def connect(creds):
682        c = context.get_netlogon_connection()
683        (auth, succ) = context.get_authenticator()
684
685        # Disable Kerberos in cli creds to extract NTLM response
686        old_state = creds.get_kerberos_state()
687        creds.set_kerberos_state(DONT_USE_KERBEROS)
688
689        logon = samlogon_logon_info(context.domain,
690                                    context.netbios_name,
691                                    creds)
692        logon_level = netlogon.NetlogonNetworkTransitiveInformation
693        validation_level = netlogon.NetlogonValidationSamInfo4
694        netr_flags = 0
695        c.netr_LogonSamLogonWithFlags(context.server,
696                                      context.machine_creds.get_workstation(),
697                                      auth,
698                                      succ,
699                                      logon_level,
700                                      logon,
701                                      validation_level,
702                                      netr_flags)
703
704        creds.set_kerberos_state(old_state)
705
706    context.last_samlogon_bad =\
707        context.with_random_bad_credentials(connect,
708                                            context.user_creds,
709                                            context.user_creds_bad,
710                                            context.last_samlogon_bad)
711    return True
712
713
714def packet_samr_0(packet, conversation, context):
715    # Open
716    c = context.get_samr_context()
717    c.get_handle()
718    return True
719
720
721def packet_samr_1(packet, conversation, context):
722    # Close
723    c = context.get_samr_context()
724    s = c.get_connection()
725    # close the last opened handle, may not always be accurate
726    # but will do for load simulation
727    if c.user_handle is not None:
728        s.Close(c.user_handle)
729        c.user_handle = None
730    elif c.group_handle is not None:
731        s.Close(c.group_handle)
732        c.group_handle = None
733    elif c.domain_handle is not None:
734        s.Close(c.domain_handle)
735        c.domain_handle = None
736        c.rids          = None
737    elif c.handle is not None:
738        s.Close(c.handle)
739        c.handle     = None
740        c.domain_sid = None
741    return True
742
743
744def packet_samr_3(packet, conversation, context):
745    # QuerySecurity
746    c = context.get_samr_context()
747    s = c.get_connection()
748    if c.user_handle is None:
749        packet_samr_34(packet, conversation, context)
750    s.QuerySecurity(c.user_handle, 1)
751    return True
752
753
754def packet_samr_5(packet, conversation, context):
755    # LookupDomain
756    c = context.get_samr_context()
757    s = c.get_connection()
758    h = c.get_handle()
759    d = lsa.String()
760    d.string = context.domain
761    c.domain_sid = s.LookupDomain(h, d)
762    return True
763
764
765def packet_samr_6(packet, conversation, context):
766    # EnumDomains
767    c = context.get_samr_context()
768    s = c.get_connection()
769    h = c.get_handle()
770    s.EnumDomains(h, 0, 0)
771    return True
772
773
774def packet_samr_7(packet, conversation, context):
775    # OpenDomain
776    c = context.get_samr_context()
777    s = c.get_connection()
778    h = c.get_handle()
779    if c.domain_sid is None:
780        packet_samr_5(packet, conversation, context)
781
782    c.domain_handle = s.OpenDomain(h,
783                                   security.SEC_FLAG_MAXIMUM_ALLOWED,
784                                   c.domain_sid)
785    return True
786
787
788SAMR_QUERY_DOMAIN_INFO_LEVELS = [8, 12]
789
790
791def packet_samr_8(packet, conversation, context):
792    # QueryDomainInfo [228]
793    c = context.get_samr_context()
794    s = c.get_connection()
795    if c.domain_handle is None:
796        packet_samr_7(packet, conversation, context)
797    level = random.choice(SAMR_QUERY_DOMAIN_INFO_LEVELS)
798    s.QueryDomainInfo(c.domain_handle, level)
799    return True
800
801
802packet_samr_14 = null_packet
803# CreateDomainAlias
804# Ignore these for now.
805
806
807def packet_samr_15(packet, conversation, context):
808    # EnumDomainAliases
809    c = context.get_samr_context()
810    s = c.get_connection()
811    if c.domain_handle is None:
812        packet_samr_7(packet, conversation, context)
813
814    s.EnumDomainAliases(c.domain_handle, 100, 0)
815    return True
816
817
818def packet_samr_16(packet, conversation, context):
819    # GetAliasMembership
820    c = context.get_samr_context()
821    s = c.get_connection()
822    if c.domain_handle is None:
823        packet_samr_7(packet, conversation, context)
824
825    sids = lsa.SidArray()
826    sid  = lsa.SidPtr()
827    sid.sid = c.domain_sid
828    sids.sids = [sid]
829    s.GetAliasMembership(c.domain_handle, sids)
830    return True
831
832
833def packet_samr_17(packet, conversation, context):
834    # LookupNames
835    c = context.get_samr_context()
836    s = c.get_connection()
837    if c.domain_handle is None:
838        packet_samr_7(packet, conversation, context)
839
840    name = lsa.String(context.username)
841    c.rids = s.LookupNames(c.domain_handle, [name])
842    return True
843
844
845def packet_samr_18(packet, conversation, context):
846    # LookupRids
847    c = context.get_samr_context()
848    s = c.get_connection()
849    if c.rids is None:
850        packet_samr_17(packet, conversation, context)
851    rids = []
852    for r in c.rids:
853        for i in r.ids:
854            rids.append(i)
855    s.LookupRids(c.domain_handle, rids)
856    return True
857
858
859def packet_samr_19(packet, conversation, context):
860    # OpenGroup
861    c = context.get_samr_context()
862    s = c.get_connection()
863    if c.domain_handle is None:
864        packet_samr_7(packet, conversation, context)
865
866    rid = 0x202  # Users I think.
867    c.group_handle = s.OpenGroup(c.domain_handle,
868                                 security.SEC_FLAG_MAXIMUM_ALLOWED,
869                                 rid)
870    return True
871
872
873def packet_samr_25(packet, conversation, context):
874    # QueryGroupMember
875    c = context.get_samr_context()
876    s = c.get_connection()
877    if c.group_handle is None:
878        packet_samr_19(packet, conversation, context)
879    s.QueryGroupMember(c.group_handle)
880    return True
881
882
883def packet_samr_34(packet, conversation, context):
884    # OpenUser
885    c = context.get_samr_context()
886    s = c.get_connection()
887    if c.rids is None:
888        packet_samr_17(packet, conversation, context)
889    c.user_handle = s.OpenUser(c.domain_handle,
890                               security.SEC_FLAG_MAXIMUM_ALLOWED,
891                               c.rids[0].ids[0])
892    return True
893
894
895def packet_samr_36(packet, conversation, context):
896    # QueryUserInfo
897    c = context.get_samr_context()
898    s = c.get_connection()
899    if c.user_handle is None:
900        packet_samr_34(packet, conversation, context)
901    level = 1
902    s.QueryUserInfo(c.user_handle, level)
903    return True
904
905
906packet_samr_37 = null_packet
907
908
909def packet_samr_39(packet, conversation, context):
910    # GetGroupsForUser
911    c = context.get_samr_context()
912    s = c.get_connection()
913    if c.user_handle is None:
914        packet_samr_34(packet, conversation, context)
915    s.GetGroupsForUser(c.user_handle)
916    return True
917
918
919packet_samr_40 = null_packet
920
921packet_samr_44 = null_packet
922
923
924def packet_samr_57(packet, conversation, context):
925    # Connect2
926    c = context.get_samr_context()
927    c.get_handle()
928    return True
929
930
931def packet_samr_64(packet, conversation, context):
932    # Connect5
933    c = context.get_samr_context()
934    c.get_handle()
935    return True
936
937
938packet_samr_68 = null_packet
939
940
941def packet_srvsvc_16(packet, conversation, context):
942    # NetShareGetInfo
943    s = context.get_srvsvc_connection()
944    server_unc = "\\\\" + context.server
945    share_name = "IPC$"
946    level = 1
947    s.NetShareGetInfo(server_unc, share_name, level)
948    return True
949
950
951def packet_srvsvc_21(packet, conversation, context):
952    """NetSrvGetInfo
953
954    FIXME: Level changed from 102 to 101 here, to bypass Windows error.
955
956    Level 102 will cause WERR_ACCESS_DENIED error against Windows, because:
957
958        > If the level is 102 or 502, the Windows implementation checks whether
959        > the caller is a member of one of the groups previously mentioned or
960        > is a member of the Power Users local group.
961
962    It passed against Samba since this check is not implemented by Samba yet.
963
964    refer to:
965
966        https://msdn.microsoft.com/en-us/library/cc247297.aspx#Appendix_A_80
967
968    """
969    srvsvc = context.get_srvsvc_connection()
970    server_unc = "\\\\" + context.server
971    level = 101
972    srvsvc.NetSrvGetInfo(server_unc, level)
973    return True
974