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 38771d4be2084d41da973b72f4bf32911621a390 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 ++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py index cfdb7b672cf..4e4a78a2319 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(self.timestamp) + src = int(self.src) + dest = int(self.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: From f63784f4392b0c814f89f9baa3a0a7041d136cc7 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 4e4a78a2319..f9d6057e568 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 7e78d8551d6fd5be8e15e9cb65a92b1a2ada2e36 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 f9d6057e568..8825a931b9d 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 e23219cfb142bfae0bd0fdb4fcc8af14a39ecaf8 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 8825a931b9d..f33f5ee927f 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 ae7292fc89a300c98a54b55c966e75377ecfa4f0 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 f33f5ee927f..8f2e35acd2e 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)