From 2cb38b070b8a4758e4b3a6ef22659b76b9baff0a Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Wed, 18 Apr 2018 15:31:12 +1200 Subject: [PATCH 01/21] traffic_replay: set gensec features to encrypt credentials While running traffic_replay script against windows dc, it will fail with a `LDAP_UNWILLING_TO_PERFORM` error for adding user. Windows requires the credentials to be encrypted before sending. `set_gensec_features` will fix it. Signed-off-by: Joe Guo --- script/traffic_replay | 3 +++ 1 file changed, 3 insertions(+) diff --git a/script/traffic_replay b/script/traffic_replay index 0e97d0a64af..df86115a48f 100755 --- a/script/traffic_replay +++ b/script/traffic_replay @@ -25,6 +25,7 @@ import shutil sys.path.insert(0, "bin/python") +from samba import gensec from samba.emulate import traffic import samba.getopt as options @@ -134,6 +135,7 @@ def main(): print_err("Removing user and machine accounts") lp = sambaopts.get_loadparm() creds = credopts.get_credentials(lp) + creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL) ldb = traffic.openLdb(host, creds, lp) traffic.clean_up_accounts(ldb, opts.instance_id) exit(0) @@ -155,6 +157,7 @@ def main(): lp = sambaopts.get_loadparm() creds = credopts.get_credentials(lp) + creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL) domain = opts.workgroup if domain: From 0c6542a9d2f338f9957b4dadf95222b125e902e3 Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Wed, 18 Apr 2018 15:36:02 +1200 Subject: [PATCH 02/21] traffic: add paged_results control for ldb search While there are more then 1000 records in the search result, a `LDAP_SIZE_LIMIT_EXCEEDED` error will be returned. Add paged_results control to fix. Signed-off-by: Joe Guo --- python/samba/emulate/traffic.py | 1 + python/samba/emulate/traffic_packets.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py index afb57da36f0..ea0529c4cb4 100644 --- a/python/samba/emulate/traffic.py +++ b/python/samba/emulate/traffic.py @@ -343,6 +343,7 @@ def generate_ldap_search_tables(self): res = db.search(db.domain_dn(), scope=ldb.SCOPE_SUBTREE, + controls=["paged_results:1:1000"], attrs=['dn']) # find a list of dns for each pattern diff --git a/python/samba/emulate/traffic_packets.py b/python/samba/emulate/traffic_packets.py index 688c935cdc0..25a02f63c2b 100644 --- a/python/samba/emulate/traffic_packets.py +++ b/python/samba/emulate/traffic_packets.py @@ -326,7 +326,10 @@ def packet_ldap_3(packet, conversation, context): samdb = context.get_ldap_connection() dn = context.get_matching_dn(dn_sig) - samdb.search(dn, scope=int(scope), attrs=attrs.split(',')) + samdb.search(dn, + scope=int(scope), + attrs=attrs.split(','), + controls=["paged_results:1:1000"]) return True From 3fb6d35da7ede94ed87421c9875a61bb8dcc28a0 Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Wed, 18 Apr 2018 15:45:10 +1200 Subject: [PATCH 03/21] traffic_packets: support NT_STATUS_NO_SUCH_DOMAIN in packet_lsarpc_39 For packet_lsarpc_39, samba will return NT_STATUS_OBJECT_NAME_NOT_FOUND, however, windows will return NT_STATUS_NO_SUCH_DOMAIN. Allow both status for now to keep compatiable with both samba and windows DC. Signed-off-by: Joe Guo --- python/samba/emulate/traffic_packets.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/python/samba/emulate/traffic_packets.py b/python/samba/emulate/traffic_packets.py index 25a02f63c2b..390041b9513 100644 --- a/python/samba/emulate/traffic_packets.py +++ b/python/samba/emulate/traffic_packets.py @@ -31,7 +31,10 @@ DONT_USE_KERBEROS ) from samba import NTSTATUSError -from samba.ntstatus import NT_STATUS_OBJECT_NAME_NOT_FOUND +from samba.ntstatus import ( + NT_STATUS_OBJECT_NAME_NOT_FOUND, + NT_STATUS_NO_SUCH_DOMAIN +) from samba.dcerpc.misc import SEC_CHAN_WKSTA import samba samba.ensure_third_party_module("dns", "dnspython") @@ -432,9 +435,11 @@ def packet_lsarpc_39(packet, conversation, context): try: c.QueryTrustedDomainInfoBySid(pol_handle, domsid, level) except NTSTATUSError as error: - # Object Not found is the expected result, anything else is a - # failure. - if not check_runtime_error(error, NT_STATUS_OBJECT_NAME_NOT_FOUND): + # Object Not found is the expected result from samba, + # while No Such Domain is the expected result from windows, + # anything else is a failure. + if not check_runtime_error(error, NT_STATUS_OBJECT_NAME_NOT_FOUND) \ + and not check_runtime_error(error, NT_STATUS_NO_SUCH_DOMAIN): raise return True From 094711ae723f7315ac87229ded74f7d490a4340e Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Thu, 26 Apr 2018 12:15:10 +1200 Subject: [PATCH 04/21] traffic: add credentials to samr lp and creds are missing in SamrContext and samr connection. While run traffic_replay against windows, this will cause `Access Denied` error. Signed-off-by: Joe Guo --- python/samba/emulate/traffic.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py index ea0529c4cb4..41ff1258519 100644 --- a/python/samba/emulate/traffic.py +++ b/python/samba/emulate/traffic.py @@ -670,7 +670,8 @@ def sasl_bind(creds): def get_samr_context(self, new=False): if not self.samr_contexts or new: - self.samr_contexts.append(SamrContext(self.server)) + self.samr_contexts.append( + SamrContext(self.server, lp=self.lp, creds=self.creds)) return self.samr_contexts[-1] def get_netlogon_connection(self): @@ -707,7 +708,7 @@ def get_authenticator(self): class SamrContext(object): """State/Context associated with a samr connection. """ - def __init__(self, server): + def __init__(self, server, lp=None, creds=None): self.connection = None self.handle = None self.domain_handle = None @@ -716,10 +717,16 @@ def __init__(self, server): self.user_handle = None self.rids = None self.server = server + self.lp = lp + self.creds = creds def get_connection(self): if not self.connection: - self.connection = samr.samr("ncacn_ip_tcp:%s" % (self.server)) + self.connection = samr.samr( + "ncacn_ip_tcp:%s[seal]" % (self.server), + lp_ctx=self.lp, + credentials=self.creds) + return self.connection def get_handle(self): From d8aa443d4b19642e91a679fcc3bb55952e70ff68 Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Fri, 27 Apr 2018 11:27:59 +1200 Subject: [PATCH 05/21] traffic_packets: replace level 102 to 101 for packet_srvsvc_21 Level 102 will cause WERR_ACCESS_DENIED error against Windows, because: > If the level is 102 or 502, the Windows implementation checks whether > the caller is a member of one of the groups previously mentioned or > is a member of the Power Users local group. It passed against Samba since this check is not implemented by Samba yet. refer to: https://msdn.microsoft.com/en-us/library/cc247297.aspx#Appendix_A_80 Signed-off-by: Joe Guo --- python/samba/emulate/traffic_packets.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/python/samba/emulate/traffic_packets.py b/python/samba/emulate/traffic_packets.py index 390041b9513..2f1691d8568 100644 --- a/python/samba/emulate/traffic_packets.py +++ b/python/samba/emulate/traffic_packets.py @@ -935,9 +935,25 @@ def packet_srvsvc_16(packet, conversation, context): def packet_srvsvc_21(packet, conversation, context): - # NetSrvGetInfo + """NetSrvGetInfo + + FIXME: Level changed from 102 to 101 here, to bypass Windows error. + + Level 102 will cause WERR_ACCESS_DENIED error against Windows, because: + + > If the level is 102 or 502, the Windows implementation checks whether + > the caller is a member of one of the groups previously mentioned or + > is a member of the Power Users local group. + + It passed against Samba since this check is not implemented by Samba yet. + + refer to: + + https://msdn.microsoft.com/en-us/library/cc247297.aspx#Appendix_A_80 + + """ srvsvc = context.get_srvsvc_connection() server_unc = "\\\\" + context.server - level = 102 + level = 101 srvsvc.NetSrvGetInfo(server_unc, level) return True From 9c92e11c8f40698fc0d58be1a8a10009d050707c Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Fri, 27 Apr 2018 12:07:16 +1200 Subject: [PATCH 06/21] traffic_packets: replace share_name from netlogon to IPC$ for packet_srvsvc_16 Sharename list for Windows: Sharename Type Comment --------- ---- ------- ADMIN$ Disk Remote Admin C$ Disk Default share IPC$ IPC Remote IPC For Samba: Sharename Type Comment --------- ---- ------- netlogon Disk sysvol Disk IPC$ IPC IPC Service While test packet_srvsvc_16 with share_name `netlogon`, it passed Samba, and got a WERR_NERR_NETNAMENOTFOUND error for Windows. Change share name to `IPC$` so Samba and Windows have it in common. Signed-off-by: Joe Guo --- python/samba/emulate/traffic_packets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/samba/emulate/traffic_packets.py b/python/samba/emulate/traffic_packets.py index 2f1691d8568..d39151fcdaa 100644 --- a/python/samba/emulate/traffic_packets.py +++ b/python/samba/emulate/traffic_packets.py @@ -928,7 +928,7 @@ def packet_srvsvc_16(packet, conversation, context): # NetShareGetInfo s = context.get_srvsvc_connection() server_unc = "\\\\" + context.server - share_name = "netlogon" + share_name = "IPC$" level = 1 s.NetShareGetInfo(server_unc, share_name, level) return True From 7522ceef9627fff6b9fe42c72719c204bde6458f Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Fri, 27 Apr 2018 14:51:11 +1200 Subject: [PATCH 07/21] traffic_packets: add windows instructions for ldap 0 simple bind To run packet_ldap_0 simple bind test against Windows, we need to install CA on Windows with following PowerShell commands: Install-windowsfeature ADCS-Cert-Authority Install-AdcsCertificationAuthority -CAType EnterpriseRootCA Restart-Computer Otherwise we will get `NT_STATUS_CONNECTION_RESET` error. Didn't change any code, just add above instructions in comment. Signed-off-by: Joe Guo --- python/samba/emulate/traffic.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py index 41ff1258519..03a24f4161c 100644 --- a/python/samba/emulate/traffic.py +++ b/python/samba/emulate/traffic.py @@ -644,6 +644,15 @@ def get_ldap_connection(self, new=False, simple=False): return self.ldap_connections[-1] def simple_bind(creds): + """ + To run simple bind against Windows, we need to run + following commands in PowerShell: + + Install-windowsfeature ADCS-Cert-Authority + Install-AdcsCertificationAuthority -CAType EnterpriseRootCA + Restart-Computer + + """ return SamDB('ldaps://%s' % self.server, credentials=creds, lp=self.lp) From e6012b062678b92b429b5e57a023c47347f42813 Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Tue, 1 May 2018 17:15:09 +1200 Subject: [PATCH 08/21] traffic_packets: add trailing $ to fix packet_rpc_netlogon_30 For `NetrServerPasswordSet2`, the 2nd arg `account_name` must end with a $, otherwise windows will return an `Access Denied` error. Use `creds.get_username()` instead of `creds.get_workstation()` to include the trailing $. Signed-off-by: Joe Guo --- python/samba/emulate/traffic_packets.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/samba/emulate/traffic_packets.py b/python/samba/emulate/traffic_packets.py index d39151fcdaa..d23a7669ad9 100644 --- a/python/samba/emulate/traffic_packets.py +++ b/python/samba/emulate/traffic_packets.py @@ -564,7 +564,9 @@ def packet_rpc_netlogon_30(packet, conversation, context): pwd.data = filler + [ord(x) for x in newpass] context.machine_creds.encrypt_netr_crypt_password(pwd) c.netr_ServerPasswordSet2(context.server, - context.machine_creds.get_workstation(), + # must ends with $, so use get_username instead + # of get_workstation here + context.machine_creds.get_username(), SEC_CHAN_WKSTA, context.netbios_name, auth, From a9d06a7bd1eb61c7f5f4f9eb6e7767cc4816f103 Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Tue, 1 May 2018 12:44:43 +1200 Subject: [PATCH 09/21] cmd_drsuapi: add dswriteaccountspn command The dswriteaccountspn command is missing in drsuapi, add it so we can use it in rpcclient. Signed-off-by: Joe Guo --- source3/rpcclient/cmd_drsuapi.c | 91 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/source3/rpcclient/cmd_drsuapi.c b/source3/rpcclient/cmd_drsuapi.c index b2221a713dd..852e2e91479 100644 --- a/source3/rpcclient/cmd_drsuapi.c +++ b/source3/rpcclient/cmd_drsuapi.c @@ -304,6 +304,96 @@ static WERROR cmd_drsuapi_getdcinfo(struct rpc_pipe_client *cli, return werr; } +static WERROR cmd_drsuapi_writeaccountspn(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + WERROR werr; + + struct GUID bind_guid; + struct policy_handle bind_handle; + struct dcerpc_binding_handle *b = cli->binding_handle; + struct drsuapi_DsNameString *spn_names = NULL; + + int i = 0; + uint32_t level_out; + union drsuapi_DsWriteAccountSpnRequest req; + union drsuapi_DsWriteAccountSpnResult result; + + if (argc < 4) { + printf("usage: %s [add|replace|delete] dn [spn_names]+\n", argv[0]); + return WERR_OK; + } + + req.req1.unknown1 = 0; /* Unused, must be 0 */ + req.req1.object_dn = argv[2]; + req.req1.count = argc - 3; + + if (strcmp(argv[1], "add") == 0) { + req.req1.operation = DRSUAPI_DS_SPN_OPERATION_ADD; + } else if (strcmp(argv[1], "replace") == 0) { + req.req1.operation = DRSUAPI_DS_SPN_OPERATION_REPLACE; + } else if (strcmp(argv[1], "delete") == 0) { + req.req1.operation = DRSUAPI_DS_SPN_OPERATION_DELETE; + } else { + printf("usage: %s [add|replace|delete] dn [spn_names]+\n", argv[0]); + return WERR_OK; + } + + spn_names = talloc_zero_array(mem_ctx, + struct drsuapi_DsNameString, + req.req1.count); + W_ERROR_HAVE_NO_MEMORY(spn_names); + + for (i=0; i Date: Thu, 10 May 2018 16:43:04 +1200 Subject: [PATCH 10/21] traffic: grant user write permission Some packets need user to have write permission, e.g.: writeaccountspn Grant user write permission then we can send packets successfully. Signed-off-by: Joe Guo --- python/samba/emulate/traffic.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py index 03a24f4161c..61ab5b64484 100644 --- a/python/samba/emulate/traffic.py +++ b/python/samba/emulate/traffic.py @@ -46,6 +46,7 @@ from samba.dsdb import UF_NORMAL_ACCOUNT from samba.dcerpc.misc import SEC_CHAN_WKSTA from samba import gensec +from samba import sd_utils SLEEP_OVERHEAD = 3e-4 @@ -1687,6 +1688,11 @@ def create_user_account(ldb, instance_id, username, userpass): "userAccountControl": str(UF_NORMAL_ACCOUNT), "unicodePwd": utf16pw }) + + # grant user write permission to do things like write account SPN + sdutils = sd_utils.SDUtils(ldb) + sdutils.dacl_add_ace(user_dn, "(A;;WP;;;PS)") + end = time.time() duration = end - start print("%f\t0\tcreate\tuser\t%f\tTrue\t" % (end, duration)) From 3f3c3e8b57aa044e6cdf2a388143abd0c5376dcd Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Thu, 10 May 2018 16:33:56 +1200 Subject: [PATCH 11/21] traffic_packets: provision request data for packet_drsuapi_13 The `drsuapi.DsWriteAccountSpnRequest1` struct in this packet was empty before. Samba lets it go but Windows will report an invalid parameter error. Provision the request with proper data. Signed-off-by: Joe Guo --- python/samba/emulate/traffic_packets.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/python/samba/emulate/traffic_packets.py b/python/samba/emulate/traffic_packets.py index d23a7669ad9..1413c8bfb80 100644 --- a/python/samba/emulate/traffic_packets.py +++ b/python/samba/emulate/traffic_packets.py @@ -242,7 +242,13 @@ def packet_drsuapi_12(packet, conversation, context): def packet_drsuapi_13(packet, conversation, context): # DsWriteAccountSpn req = drsuapi.DsWriteAccountSpnRequest1() - req.operation = drsuapi.DRSUAPI_DS_SPN_OPERATION_ADD + req.operation = drsuapi.DRSUAPI_DS_SPN_OPERATION_REPLACE + req.unknown1 = 0 # Unused, must be 0 + req.object_dn = context.user_dn + req.count = 1 # only 1 name + spn_name = drsuapi.DsNameString() + spn_name.str = 'foo/{}'.format(context.username) + req.spn_names = [spn_name] (drs, handle) = context.get_drsuapi_connection_pair() (level, res) = drs.DsWriteAccountSpn(handle, 1, req) return True From 150c48faf1ce3f2f4315c23ce74f813ab8234ac6 Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Wed, 2 May 2018 05:04:03 +0000 Subject: [PATCH 12/21] traffic: set domain on user_creds and machine_creds The domain is missing in traffic user and machine credential, this will cause some packet tests fail against windows. Signed-off-by: Joe Guo --- python/samba/emulate/traffic.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py index 61ab5b64484..d65aec6f32c 100644 --- a/python/samba/emulate/traffic.py +++ b/python/samba/emulate/traffic.py @@ -457,6 +457,7 @@ def generate_user_creds(self): self.user_creds.set_workstation(self.netbios_name) self.user_creds.set_password(self.userpass) self.user_creds.set_username(self.username) + self.user_creds.set_domain(self.domain) if self.prefer_kerberos: self.user_creds.set_kerberos_state(MUST_USE_KERBEROS) else: @@ -514,6 +515,7 @@ def generate_machine_creds(self): self.machine_creds.set_secure_channel_type(SEC_CHAN_WKSTA) self.machine_creds.set_password(self.machinepass) self.machine_creds.set_username(self.netbios_name + "$") + self.machine_creds.set_domain(self.domain) if self.prefer_kerberos: self.machine_creds.set_kerberos_state(MUST_USE_KERBEROS) else: From f338a31f3f31be0532a0abea7f57ec38641b875e Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Wed, 2 May 2018 21:40:39 +0000 Subject: [PATCH 13/21] pycredentials: add py_creds_get_secure_channel_type We have only set, need get. Signed-off-by: Joe Guo --- auth/credentials/pycredentials.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/auth/credentials/pycredentials.c b/auth/credentials/pycredentials.c index 68bb3060a99..c626e3fa8a0 100644 --- a/auth/credentials/pycredentials.c +++ b/auth/credentials/pycredentials.c @@ -680,6 +680,16 @@ static PyObject *py_creds_set_secure_channel_type(PyObject *self, PyObject *args Py_RETURN_NONE; } +static PyObject *py_creds_get_secure_channel_type(PyObject *self, PyObject *args) +{ + enum netr_SchannelType channel_type = SEC_CHAN_NULL; + + channel_type = cli_credentials_get_secure_channel_type( + PyCredentials_AsCliCredentials(self)); + + return PyInt_FromLong(channel_type); +} + static PyObject *py_creds_encrypt_netr_crypt_password(PyObject *self, PyObject *args) { @@ -815,6 +825,8 @@ static PyMethodDef py_creds_methods[] = { "Get a new client NETLOGON_AUTHENTICATOR"}, { "set_secure_channel_type", py_creds_set_secure_channel_type, METH_VARARGS, NULL }, + { "get_secure_channel_type", py_creds_get_secure_channel_type, + METH_VARARGS }, { "encrypt_netr_crypt_password", py_creds_encrypt_netr_crypt_password, METH_VARARGS, From a3de78796222e0720737b324e5dde287b2fe9af4 Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Wed, 2 May 2018 22:12:51 +0000 Subject: [PATCH 14/21] traffic: change machine creds secure channel type SEC_CHAN_WKSTA --> SEC_CHAN_BDC This will fix netlogon failure against windows. Signed-off-by: Joe Guo --- python/samba/emulate/traffic.py | 6 +++--- python/samba/emulate/traffic_packets.py | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py index d65aec6f32c..f8f52e8f326 100644 --- a/python/samba/emulate/traffic.py +++ b/python/samba/emulate/traffic.py @@ -44,7 +44,7 @@ from samba.auth import system_session from samba.dsdb import UF_WORKSTATION_TRUST_ACCOUNT, UF_PASSWD_NOTREQD from samba.dsdb import UF_NORMAL_ACCOUNT -from samba.dcerpc.misc import SEC_CHAN_WKSTA +from samba.dcerpc.misc import SEC_CHAN_BDC from samba import gensec from samba import sd_utils @@ -512,7 +512,7 @@ def generate_machine_creds(self): self.machine_creds = Credentials() self.machine_creds.guess(self.lp) self.machine_creds.set_workstation(self.netbios_name) - self.machine_creds.set_secure_channel_type(SEC_CHAN_WKSTA) + self.machine_creds.set_secure_channel_type(SEC_CHAN_BDC) self.machine_creds.set_password(self.machinepass) self.machine_creds.set_username(self.netbios_name + "$") self.machine_creds.set_domain(self.domain) @@ -524,7 +524,7 @@ def generate_machine_creds(self): self.machine_creds_bad = Credentials() self.machine_creds_bad.guess(self.lp) self.machine_creds_bad.set_workstation(self.netbios_name) - self.machine_creds_bad.set_secure_channel_type(SEC_CHAN_WKSTA) + self.machine_creds_bad.set_secure_channel_type(SEC_CHAN_BDC) self.machine_creds_bad.set_password(self.machinepass[:-4]) self.machine_creds_bad.set_username(self.netbios_name + "$") if self.prefer_kerberos: diff --git a/python/samba/emulate/traffic_packets.py b/python/samba/emulate/traffic_packets.py index 1413c8bfb80..3f5db4317a3 100644 --- a/python/samba/emulate/traffic_packets.py +++ b/python/samba/emulate/traffic_packets.py @@ -35,7 +35,6 @@ NT_STATUS_OBJECT_NAME_NOT_FOUND, NT_STATUS_NO_SUCH_DOMAIN ) -from samba.dcerpc.misc import SEC_CHAN_WKSTA import samba samba.ensure_third_party_module("dns", "dnspython") import dns.resolver @@ -573,7 +572,7 @@ def packet_rpc_netlogon_30(packet, conversation, context): # must ends with $, so use get_username instead # of get_workstation here context.machine_creds.get_username(), - SEC_CHAN_WKSTA, + context.machine_creds.get_secure_channel_type(), context.netbios_name, auth, pwd) From 81165db8814e898e9d11c6106e7985ecff1ae0c8 Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Wed, 2 May 2018 22:22:52 +0000 Subject: [PATCH 15/21] traffic: fix userAccountControl for machine account change userAccountControl from UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD to UF_TRUSTED_FOR_DELEGATION | UF_SERVER_TRUST_ACCOUNT This will fix NetrServerPasswordSet2 failure in packet_rpc_netlogon_30 while testing against windows. Signed-off-by: Joe Guo --- python/samba/emulate/traffic.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py index f8f52e8f326..cfdb7b672cf 100644 --- a/python/samba/emulate/traffic.py +++ b/python/samba/emulate/traffic.py @@ -42,8 +42,11 @@ import traceback from samba.credentials import Credentials, DONT_USE_KERBEROS, MUST_USE_KERBEROS from samba.auth import system_session -from samba.dsdb import UF_WORKSTATION_TRUST_ACCOUNT, UF_PASSWD_NOTREQD -from samba.dsdb import UF_NORMAL_ACCOUNT +from samba.dsdb import ( + UF_NORMAL_ACCOUNT, + UF_SERVER_TRUST_ACCOUNT, + UF_TRUSTED_FOR_DELEGATION +) from samba.dcerpc.misc import SEC_CHAN_BDC from samba import gensec from samba import sd_utils @@ -1668,7 +1671,7 @@ def create_machine_account(ldb, instance_id, netbios_name, machinepass): "objectclass": "computer", "sAMAccountName": "%s$" % netbios_name, "userAccountControl": - str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD), + str(UF_TRUSTED_FOR_DELEGATION | UF_SERVER_TRUST_ACCOUNT), "unicodePwd": utf16pw}) end = time.time() duration = end - start From aab70f8836a3b1f56e44036668b4095f65b6321d Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Mon, 7 May 2018 10:18:42 +1200 Subject: [PATCH 16/21] traffic_replay: fetch domain from creds other than opts For traffic_replay script, when user provides `--workgroup` or `-W` option from command line, it will be set on the creds option group, other than the opts one. So while checking this option, we should check it against creds. The previous code is actually loading domain from lp, which get data from the smb.conf file. Signed-off-by: Joe Guo --- script/traffic_replay | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/traffic_replay b/script/traffic_replay index df86115a48f..43a0fb5d8a7 100755 --- a/script/traffic_replay +++ b/script/traffic_replay @@ -159,7 +159,7 @@ def main(): creds = credopts.get_credentials(lp) creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL) - domain = opts.workgroup + domain = creds.get_domain() if domain: lp.set("workgroup", domain) else: From 41cfa80eaff9f20c0a20f1407f13777774ecf740 Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Thu, 10 May 2018 14:53:55 +1200 Subject: [PATCH 17/21] traffic: optimize packet init for better performance When we run traffic_replay, we are creating millions of Packet objects. So small change in Packet.__init__ will make big difference. By initializing packet with converted values without parsing string, the time cost for 3961148 calls of Packet.__init__ dcrease from 17s to 4s, according to cProfile. Signed-off-by: Joe Guo --- python/samba/emulate/traffic.py | 70 ++++++----- python/samba/tests/emulate/traffic_packet.py | 181 ++++++++++++++------------- 2 files changed, 129 insertions(+), 122 deletions(-) diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py index cfdb7b672cf..b89d9521c56 100644 --- a/python/samba/emulate/traffic.py +++ b/python/samba/emulate/traffic.py @@ -138,10 +138,26 @@ class FakePacketError(Exception): class Packet(object): """Details of a network packet""" - def __init__(self, fields): - if isinstance(fields, str): - fields = fields.rstrip('\n').split('\t') + def __init__(self, timestamp, ip_protocol, stream_number, src, dest, + protocol, opcode, desc, extra): + self.timestamp = timestamp + self.ip_protocol = ip_protocol + self.stream_number = stream_number + self.src = src + self.dest = dest + self.protocol = protocol + self.opcode = opcode + self.desc = desc + self.extra = extra + if self.src < self.dest: + self.endpoints = (self.src, self.dest) + else: + self.endpoints = (self.dest, self.src) + + @classmethod + def from_line(self, line): + fields = line.rstrip('\n').split('\t') (timestamp, ip_protocol, stream_number, @@ -152,23 +168,12 @@ def __init__(self, fields): desc) = fields[:8] extra = fields[8:] - self.timestamp = float(timestamp) - self.ip_protocol = ip_protocol - try: - self.stream_number = int(stream_number) - except (ValueError, TypeError): - self.stream_number = None - self.src = int(src) - self.dest = int(dest) - self.protocol = protocol - self.opcode = opcode - self.desc = desc - self.extra = extra + timestamp = float(timestamp) + src = int(src) + dest = int(dest) - if self.src < self.dest: - self.endpoints = (self.src, self.dest) - else: - self.endpoints = (self.dest, self.src) + return Packet(timestamp, ip_protocol, stream_number, src, dest, + protocol, opcode, desc, extra) def as_summary(self, time_offset=0.0): """Format the packet as a traffic_summary line. @@ -196,14 +201,15 @@ def __repr__(self): return "" % self def copy(self): - return self.__class__([self.timestamp, - self.ip_protocol, - self.stream_number, - self.src, - self.dest, - self.protocol, - self.opcode, - self.desc] + self.extra) + return self.__class__(self.timestamp, + self.ip_protocol, + self.stream_number, + self.src, + self.dest, + self.protocol, + self.opcode, + self.desc, + self.extra) def as_packet_type(self): t = '%s:%s' % (self.protocol, self.opcode) @@ -809,11 +815,9 @@ def add_short_packet(self, timestamp, p, extra, client=True): desc = OP_DESCRIPTIONS.get((protocol, opcode), '') ip_protocol = IP_PROTOCOLS.get(protocol, '06') - fields = [timestamp - self.start_time, ip_protocol, - '', src, dest, - protocol, opcode, desc] - fields.extend(extra) - packet = Packet(fields) + packet = Packet(timestamp - self.start_time, ip_protocol, + '', src, dest, + protocol, opcode, desc, extra) # XXX we're assuming the timestamp is already adjusted for # this conversation? # XXX should we adjust client balance for guessed packets? @@ -1035,7 +1039,7 @@ def ingest_summaries(files, dns_mode='count'): f = open(f) print("Ingesting %s" % (f.name,), file=sys.stderr) for line in f: - p = Packet(line) + p = Packet.from_line(line) if p.protocol == 'dns' and dns_mode != 'include': dns_counts[p.opcode] += 1 else: diff --git a/python/samba/tests/emulate/traffic_packet.py b/python/samba/tests/emulate/traffic_packet.py index 8aa6ca03247..27afe0e8273 100644 --- a/python/samba/tests/emulate/traffic_packet.py +++ b/python/samba/tests/emulate/traffic_packet.py @@ -25,6 +25,7 @@ from samba.credentials import MUST_USE_KERBEROS, DONT_USE_KERBEROS from samba.emulate import traffic_packets as p from samba.emulate import traffic +from samba.emulate.traffic import Packet from samba.samdb import SamDB import samba.tests @@ -85,56 +86,58 @@ def tearDown(self): shutil.rmtree(self.tempdir) def test_packet_cldap_03(self): - packet = traffic.Packet("0.0\t11\t1\t2\t1\tcldap\t3\tsearchRequest\t") + packet = Packet.from_line( + "0.0\t11\t1\t2\t1\tcldap\t3\tsearchRequest\t") self.assertTrue(p.packet_cldap_3(packet, self.conversation, self. context)) def test_packet_cldap_05(self): - packet = traffic.Packet("0.0\t11\t1\t1\t2\tcldap\t5\tsearchResDone\t") + packet = Packet.from_line( + "0.0\t11\t1\t1\t2\tcldap\t5\tsearchResDone\t") self.assertFalse(p.packet_cldap_5(packet, self.conversation, self. context)) def test_packet_dcerpc_00(self): - packet = traffic.Packet("0.0\t11\t1\t2\t1\tdcerpc\t0\tRequest\t") + packet = Packet.from_line("0.0\t11\t1\t2\t1\tdcerpc\t0\tRequest\t") self.assertFalse(p.packet_dcerpc_0(packet, self.conversation, self. context)) def test_packet_dcerpc_02(self): - packet = traffic.Packet("0.0\t11\t1\t1\t2\tdcerpc\t2\tResponse\t") + packet = Packet.from_line("0.0\t11\t1\t1\t2\tdcerpc\t2\tResponse\t") self.assertFalse(p.packet_dcerpc_2(packet, self.conversation, self. context)) def test_packet_dcerpc_03(self): - packet = traffic.Packet("0.0\t11\t1\t1\t2\tdcerpc\t3\t\t") + packet = Packet.from_line("0.0\t11\t1\t1\t2\tdcerpc\t3\t\t") self.assertFalse(p.packet_dcerpc_3(packet, self.conversation, self. context)) def test_packet_dcerpc_11(self): - packet = traffic.Packet("0.0\t11\t1\t2\t1\tdcerpc\t11\tBind\t") + packet = Packet.from_line("0.0\t11\t1\t2\t1\tdcerpc\t11\tBind\t") self.assertFalse(p.packet_dcerpc_11(packet, self.conversation, self. context)) def test_packet_dcerpc_13(self): - packet = traffic.Packet("0.0\t11\t1\t2\t1\tdcerpc\t13\t\t") + packet = Packet.from_line("0.0\t11\t1\t2\t1\tdcerpc\t13\t\t") self.assertFalse(p.packet_dcerpc_13(packet, self.conversation, self. context)) def test_packet_dcerpc_14(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t11\t1\t2\t1\tdcerpc\t14\tAlter_context\t") self.assertFalse(p.packet_dcerpc_14(packet, self.conversation, self. context)) def test_packet_dcerpc_15(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t11\t1\t1\t2\tdcerpc\t15\tAlter_context_resp\t") # Set user_creds MUST_USE_KERBEROS to suppress the warning message. self.context.user_creds.set_kerberos_state(MUST_USE_KERBEROS) @@ -143,70 +146,70 @@ def test_packet_dcerpc_15(self): self. context)) def test_packet_dcerpc_16(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t11\t1\t1\t2\tdcerpc\t16\tAUTH3\t") self.assertFalse(p.packet_dcerpc_16(packet, self.conversation, self. context)) def test_packet_dns_01(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t11\t1\t1\t2\tdns\t1\tresponse\t") self.assertFalse(p.packet_dns_1(packet, self.conversation, self. context)) def test_packet_drsuapi_00(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t1\t2\tdrsuapi\t0\tDsBind\t") self.assertTrue(p.packet_drsuapi_0(packet, self.conversation, self. context)) def test_packet_drsuapi_01(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t1\t2\tdrsuapi\t1\tDsUnBind\t") self.assertTrue(p.packet_drsuapi_1(packet, self.conversation, self. context)) def test_packet_drsuapi_02(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t1\t2\tdrsuapi\t2\tDsReplicaSync\t") self.assertFalse(p.packet_drsuapi_2(packet, self.conversation, self. context)) def test_packet_drsuapi_03(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t1\t2\tdrsuapi\t3\tDsGetNCChanges\t") self.assertFalse(p.packet_drsuapi_3(packet, self.conversation, self. context)) def test_packet_drsuapi_04(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t1\t2\tdrsuapi\t4\tDsReplicaUpdateRefs\t") self.assertFalse(p.packet_drsuapi_4(packet, self.conversation, self. context)) def test_packet_drsuapi_12(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t1\t2\tdrsuapi\t12\tDsCrackNames\t") self.assertTrue(p.packet_drsuapi_12(packet, self.conversation, self. context)) def test_packet_drsuapi_13(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t1\t2\tdrsuapi\t13\tDsWriteAccountSpn\t") self.assertTrue(p.packet_drsuapi_13(packet, self.conversation, self. context)) def test_packet_epm_03(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t1\t2\tepm\t3\tMap\t") self.assertFalse(p.packet_epm_3(packet, self.conversation, @@ -216,7 +219,7 @@ def test_packet_kerberos(self): """Kerberos packets are not generated, but are used as a hint to favour kerberos. """ - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t11\t1\t1\t2\tkerberos\t\t\t") self.assertFalse(p.packet_kerberos_(packet, self.conversation, @@ -237,14 +240,14 @@ def test_packet_kerberos(self): self.credentials.set_kerberos_state(DONT_USE_KERBEROS) def test_packet_ldap(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t1\t2\tldap\t\t*** Unknown ***\t") self.assertFalse(p.packet_ldap_(packet, self.conversation, self. context)) def test_packet_ldap_00_sasl(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tldap\t0\tbindRequest" "\t\t\t\t\t3\tsasl\t1.3.6.1.5.5.2") self.assertTrue(p.packet_ldap_0(packet, @@ -252,7 +255,7 @@ def test_packet_ldap_00_sasl(self): self. context)) def test_packet_ldap_00_simple(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tldap\t0\tbindRequest" "\t\t\t\t\t0\tsimple\t") self.assertTrue(p.packet_ldap_0(packet, @@ -260,21 +263,21 @@ def test_packet_ldap_00_simple(self): self. context)) def test_packet_ldap_01(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t1\t2\tldap\t1\tbindResponse\t") self.assertFalse(p.packet_ldap_1(packet, self.conversation, self. context)) def test_packet_ldap_02(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tldap\t2\tunbindRequest\t") self.assertFalse(p.packet_ldap_2(packet, self.conversation, self. context)) def test_packet_ldap_03(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tldap\t3\tsearchRequest" "\t2\tDC,DC\t\tcn\t\t\t") self.assertTrue(p.packet_ldap_3(packet, @@ -282,21 +285,21 @@ def test_packet_ldap_03(self): self. context)) def test_packet_ldap_04(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t1\t2\tldap\t4\tsearchResEntry\t") self.assertFalse(p.packet_ldap_4(packet, self.conversation, self. context)) def test_packet_ldap_05(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t1\t2\tldap\t5\tsearchResDone\t") self.assertFalse(p.packet_ldap_5(packet, self.conversation, self. context)) def test_packet_ldap_06(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tldap\t6\tmodifyRequest\t" "\t\t\t\t0\tadd") self.assertFalse(p.packet_ldap_6(packet, @@ -304,420 +307,420 @@ def test_packet_ldap_06(self): self. context)) def test_packet_ldap_07(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t1\t2\tldap\t7\tmodifyResponse\t") self.assertFalse(p.packet_ldap_7(packet, self.conversation, self. context)) def test_packet_ldap_08(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tldap\t8\taddRequest\t") self.assertFalse(p.packet_ldap_8(packet, self.conversation, self. context)) def test_packet_ldap_09(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t1\t2\tldap\t9\taddResponse\t") self.assertFalse(p.packet_ldap_9(packet, self.conversation, self. context)) def test_packet_ldap_16(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tldap\t16\tabandonRequest\t") self.assertFalse(p.packet_ldap_16(packet, self.conversation, self. context)) def test_packet_lsarpc_00(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tlsarpc\t0\tlsa_Close\t") self.assertFalse(p.packet_lsarpc_1(packet, self.conversation, self. context)) def test_packet_lsarpc_01(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tlsarpc\t1\tlsa_Delete\t") self.assertFalse(p.packet_lsarpc_1(packet, self.conversation, self. context)) def test_packet_lsarpc_02(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tlsarpc\t2\tlsa_EnumeratePrivileges\t") self.assertFalse(p.packet_lsarpc_2(packet, self.conversation, self. context)) def test_packet_lsarpc_03(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tlsarpc\t3\tlsa_QuerySecurityObject\t") self.assertFalse(p.packet_lsarpc_3(packet, self.conversation, self. context)) def test_packet_lsarpc_04(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tlsarpc\t4\tlsa_SetSecurityObject\t") self.assertFalse(p.packet_lsarpc_4(packet, self.conversation, self. context)) def test_packet_lsarpc_05(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tlsarpc\t5\tlsa_ChangePassword\t") self.assertFalse(p.packet_lsarpc_5(packet, self.conversation, self. context)) def test_packet_lsarpc_06(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tlsarpc\t6\tlsa_OpenPolicy\t") self.assertFalse(p.packet_lsarpc_6(packet, self.conversation, self. context)) def test_packet_lsarpc_14(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tlsarpc\t14\tlsa_LookupNames\t") self.assertTrue(p.packet_lsarpc_14(packet, self.conversation, self. context)) def test_packet_lsarpc_15(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tlsarpc\t15\tlsa_LookupSids\t") self.assertTrue(p.packet_lsarpc_15(packet, self.conversation, self. context)) def test_packet_lsarpc_39(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tlsarpc\t39\tlsa_QueryTrustedDomainInfoBySid\t") self.assertTrue(p.packet_lsarpc_39(packet, self.conversation, self. context)) def test_packet_lsarpc_40(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tlsarpc\t40\tlsa_SetTrustedDomainInfo\t") self.assertFalse(p.packet_lsarpc_40(packet, self.conversation, self. context)) def test_packet_lsarpc_43(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tlsarpc\t43\tlsa_StorePrivateData\t") self.assertFalse(p.packet_lsarpc_43(packet, self.conversation, self. context)) def test_packet_lsarpc_44(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tlsarpc\t44\tlsa_RetrievePrivateData\t") self.assertFalse(p.packet_lsarpc_44(packet, self.conversation, self. context)) def test_packet_lsarpc_68(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tlsarpc\t68\tlsa_LookupNames3\t") self.assertFalse(p.packet_lsarpc_68(packet, self.conversation, self. context)) def test_packet_lsarpc_76(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tlsarpc\t76\tlsa_LookupSids3\t") self.assertTrue(p.packet_lsarpc_76(packet, self.conversation, self. context)) def test_packet_lsarpc_77(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tlsarpc\t77\tlsa_LookupNames4\t") self.assertTrue(p.packet_lsarpc_77(packet, self.conversation, self. context)) def test_packet_nbns_00(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tnbns\t0\tquery\t") self.assertTrue(p.packet_nbns_0(packet, self.conversation, self. context)) def test_packet_nbns_01(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t1\t2\tnbns\t1\tresponse\t") self.assertTrue(p.packet_nbns_0(packet, self.conversation, self. context)) def test_packet_rpc_netlogon_00(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\trpc_netlogon\t0\tNetrLogonUasLogon\t") self.assertFalse(p.packet_rpc_netlogon_0(packet, self.conversation, self. context)) def test_packet_rpc_netlogon_01(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\trpc_netlogon\t1\tNetrLogonUasLogoff\t") self.assertFalse(p.packet_rpc_netlogon_1(packet, self.conversation, self. context)) def test_packet_rpc_netlogon_04(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\trpc_netlogon\t4\tNetrServerReqChallenge\t") self.assertFalse(p.packet_rpc_netlogon_4(packet, self.conversation, self. context)) def test_packet_rpc_netlogon_14(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\trpc_netlogon\t14\tNetrLogonControl2\t") self.assertFalse(p.packet_rpc_netlogon_14(packet, self.conversation, self. context)) def test_packet_rpc_netlogon_15(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\trpc_netlogon\t15\tNetrServerAuthenticate2\t") self.assertFalse(p.packet_rpc_netlogon_15(packet, self.conversation, self. context)) def test_packet_rpc_netlogon_21(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\trpc_netlogon\t21\tNetrLogonDummyRoutine1\t") self.assertFalse(p.packet_rpc_netlogon_21(packet, self.conversation, self. context)) def test_packet_rpc_netlogon_26(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\trpc_netlogon\t26\tNetrServerAuthenticate3\t") self.assertFalse(p.packet_rpc_netlogon_26(packet, self.conversation, self. context)) def test_packet_rpc_netlogon_29(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\trpc_netlogon\t29\tNetrLogonGetDomainInfo\t") self.assertTrue(p.packet_rpc_netlogon_29(packet, self.conversation, self. context)) def test_packet_rpc_netlogon_30(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\trpc_netlogon\t30\tNetrServerPasswordSet2\t") self.assertTrue(p.packet_rpc_netlogon_30(packet, self.conversation, self. context)) def test_packet_rpc_netlogon_34(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\trpc_netlogon\t34\tDsrGetDcNameEx2\t") self.assertFalse(p.packet_rpc_netlogon_34(packet, self.conversation, self. context)) def test_packet_rpc_netlogon_39(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\trpc_netlogon\t39\tNetrLogonSamLogonEx\t") self.assertTrue(p.packet_rpc_netlogon_39(packet, self.conversation, self. context)) def test_packet_rpc_netlogon_40(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\trpc_netlogon\t40\tDsrEnumerateDomainTrusts\t") self.assertTrue(p.packet_rpc_netlogon_40(packet, self.conversation, self. context)) def test_packet_rpc_netlogon_45(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\trpc_netlogon\t45\tNetrLogonSamLogonWithFlags\t") self.assertTrue(p.packet_rpc_netlogon_45(packet, self.conversation, self. context)) def test_packet_samr_00(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t0\tConnect\t") self.assertTrue(p.packet_samr_0(packet, self.conversation, self. context)) def test_packet_samr_01(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t1\tClose\t") self.assertTrue(p.packet_samr_1(packet, self.conversation, self. context)) def test_packet_samr_03(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t3\tQuerySecurity\t") self.assertTrue(p.packet_samr_3(packet, self.conversation, self. context)) def test_packet_samr_05(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t5\tLookupDomain\t") self.assertTrue(p.packet_samr_5(packet, self.conversation, self. context)) def test_packet_samr_06(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t6\tEnumDomains\t") self.assertTrue(p.packet_samr_6(packet, self.conversation, self. context)) def test_packet_samr_07(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t7\tOpenDomain\t") self.assertTrue(p.packet_samr_7(packet, self.conversation, self. context)) def test_packet_samr_08(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t8\tQueryDomainInfo'\t") self.assertTrue(p.packet_samr_8(packet, self.conversation, self. context)) def test_packet_samr_14(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t14\tCreateDomAlias\t") self.assertFalse(p.packet_samr_14(packet, self.conversation, self. context)) def test_packet_samr_15(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t15\tEnumDomainAliases\t") self.assertTrue(p.packet_samr_15(packet, self.conversation, self. context)) def test_packet_samr_16(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t16\tGetAliasMembership\t") self.assertTrue(p.packet_samr_16(packet, self.conversation, self. context)) def test_packet_samr_17(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t17\tLookupNames\t") self.assertTrue(p.packet_samr_17(packet, self.conversation, self. context)) def test_packet_samr_18(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t18\tLookupRids\t") self.assertTrue(p.packet_samr_18(packet, self.conversation, self. context)) def test_packet_samr_19(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t19\tOpenGroup\t") self.assertTrue(p.packet_samr_19(packet, self.conversation, self. context)) def test_packet_samr_25(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t25\tQueryGroupMember\t") self.assertTrue(p.packet_samr_25(packet, self.conversation, self. context)) def test_packet_samr_34(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t34\tOpenUser\t") self.assertTrue(p.packet_samr_34(packet, self.conversation, self. context)) def test_packet_samr_36(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t36\tQueryUserInfo\t") self.assertTrue(p.packet_samr_36(packet, self.conversation, self. context)) def test_packet_samr_37(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t37\tSetUserInfo\t") self.assertFalse(p.packet_samr_37(packet, self.conversation, self. context)) def test_packet_samr_39(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t39\tGetGroupsForUser\t") self.assertTrue(p.packet_samr_39(packet, self.conversation, self. context)) def test_packet_samr_40(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t40\tQueryDisplayInfo\t") self.assertFalse(p.packet_samr_40(packet, self.conversation, self. context)) def test_packet_samr_44(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t44\tGetUserPwInfo\t") self.assertFalse(p.packet_samr_44(packet, self.conversation, self. context)) def test_packet_samr_57(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t57\tConnect2\t") self.assertTrue(p.packet_samr_57(packet, self.conversation, self. context)) def test_packet_samr_64(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t64\tConnect5\t") self.assertTrue(p.packet_samr_64(packet, self.conversation, self. context)) def test_packet_samr_68(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsamr\t68\t\t") self.assertFalse(p.packet_samr_68(packet, self.conversation, self. context)) def test_packet_srvsvc_16(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsrvsvc\t16\tNetShareGetInfo\t") self.assertTrue(p.packet_srvsvc_16(packet, self.conversation, self. context)) def test_packet_srvsvc_21(self): - packet = traffic.Packet( + packet = Packet.from_line( "0.0\t06\t1\t2\t1\tsrvsvc\t21\tNetSrvGetInfo\t") self.assertTrue(p.packet_srvsvc_21(packet, self.conversation, From 6e998a23b3a50981b9065dfbe616e75085b815ba Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Thu, 10 May 2018 17:01:19 +1200 Subject: [PATCH 18/21] traffic: simplify forget_packets_outside_window Make code compact, and improve performance a little bit. Signed-off-by: Joe Guo --- python/samba/emulate/traffic.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py index b89d9521c56..abd8a80598f 100644 --- a/python/samba/emulate/traffic.py +++ b/python/samba/emulate/traffic.py @@ -955,18 +955,8 @@ def forget_packets_outside_window(self, s, e): :param s: start of the window :param e: end of the window """ - - new_packets = [] - for p in self.packets: - if p.timestamp < s or p.timestamp > e: - continue - new_packets.append(p) - - self.packets = new_packets - if new_packets: - self.start_time = new_packets[0].timestamp - else: - self.start_time = None + self.packets = [p for p in self.packets if s <= p.timestamp <= e] + self.start_time = self.packets[0].timestamp if self.packets else None def renormalise_times(self, start_time): """Adjust the packet start times relative to the new start time.""" From dbc9ffb74b0fbccd6b0d38dc84ecfa33dff878d1 Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Thu, 10 May 2018 17:04:50 +1200 Subject: [PATCH 19/21] traffic: improve add_short_packet by avoiding str.split Avoid str.split, which will repeat for each packet. Signed-off-by: Joe Guo --- python/samba/emulate/traffic.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py index abd8a80598f..07db7e72027 100644 --- a/python/samba/emulate/traffic.py +++ b/python/samba/emulate/traffic.py @@ -803,12 +803,12 @@ def add_packet(self, packet): if p.is_really_a_packet(): self.packets.append(p) - def add_short_packet(self, timestamp, p, extra, client=True): + def add_short_packet(self, timestamp, protocol, opcode, extra, + client=True): """Create a packet from a timestamp, and 'protocol:opcode' pair, and a (possibly empty) list of extra data. If client is True, assume this packet is from the client to the server. """ - protocol, opcode = p.split(':', 1) src, dest = self.guess_client_server() if not client: src, dest = dest, src @@ -1227,7 +1227,7 @@ def construct_conversation(self, timestamp=0.0, client=2, server=1, timestamp += wait if hard_stop is not None and timestamp > hard_stop: break - c.add_short_packet(timestamp, p, extra) + c.add_short_packet(timestamp, protocol, opcode, extra) key = key[1:] + (p,) From f40c3b743b34307520d3859616d1b398a01fc469 Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Thu, 10 May 2018 17:11:29 +1200 Subject: [PATCH 20/21] traffic: improve is_really_a_packet This function will repeat on each packet. Avoid exception for getattr, which is expensive for performance. Signed-off-by: Joe Guo --- python/samba/emulate/traffic.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py index 07db7e72027..227477a5425 100644 --- a/python/samba/emulate/traffic.py +++ b/python/samba/emulate/traffic.py @@ -282,13 +282,12 @@ def is_really_a_packet(self, missing_packet_stats=None): return False fn_name = 'packet_%s_%s' % (self.protocol, self.opcode) - try: - fn = getattr(traffic_packets, fn_name) - if fn is traffic_packets.null_packet: - return False - except AttributeError: + fn = getattr(traffic_packets, fn_name, None) + if not fn: print("missing packet %s" % fn_name, file=sys.stderr) return False + if fn is traffic_packets.null_packet: + return False return True From 620b3ab7a903e6e2709cc8349c89fbbb3fe2e289 Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Thu, 10 May 2018 17:23:02 +1200 Subject: [PATCH 21/21] traffic: improve add_short_packet by avoiding dict.get dict.get is slower than []. Avoid get to improve performance. (For 3989418 calls, total time decease from 9.395 to 8.573) Signed-off-by: Joe Guo --- python/samba/emulate/traffic.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py index 227477a5425..db0fcf7788b 100644 --- a/python/samba/emulate/traffic.py +++ b/python/samba/emulate/traffic.py @@ -811,9 +811,12 @@ def add_short_packet(self, timestamp, protocol, opcode, extra, src, dest = self.guess_client_server() if not client: src, dest = dest, src - - desc = OP_DESCRIPTIONS.get((protocol, opcode), '') - ip_protocol = IP_PROTOCOLS.get(protocol, '06') + key = (protocol, opcode) + desc = OP_DESCRIPTIONS[key] if key in OP_DESCRIPTIONS else '' + if protocol in IP_PROTOCOLS: + ip_protocol = IP_PROTOCOLS[protocol] + else: + ip_protocol = '06' packet = Packet(timestamp - self.start_time, ip_protocol, '', src, dest, protocol, opcode, desc, extra)