mirror of
https://github.com/samba-team/samba.git
synced 2025-01-12 09:18:10 +03:00
5cb8805811
Signed-off-by: Rob van der Linde <rob@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz> Autobuild-User(master): Andrew Bartlett <abartlet@samba.org> Autobuild-Date(master): Thu Feb 23 23:33:46 UTC 2023 on atb-devel-224
1178 lines
46 KiB
Python
1178 lines
46 KiB
Python
# Unix SMB/CIFS implementation.
|
|
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2010
|
|
# Copyright (C) Stefan Metzmacher 2014,2015
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
import sys
|
|
import socket
|
|
import samba.dcerpc.dcerpc as dcerpc
|
|
import samba.dcerpc.base
|
|
import samba.dcerpc.epmapper
|
|
import samba.dcerpc.security as security
|
|
import samba.tests
|
|
from samba import gensec
|
|
from samba.credentials import Credentials
|
|
from samba.tests import TestCase
|
|
from samba.ndr import ndr_pack, ndr_unpack, ndr_unpack_out
|
|
from samba.ntstatus import (
|
|
NT_STATUS_CONNECTION_DISCONNECTED,
|
|
NT_STATUS_PIPE_DISCONNECTED,
|
|
NT_STATUS_IO_TIMEOUT
|
|
)
|
|
from samba import NTSTATUSError
|
|
from samba.samba3 import param as s3param
|
|
from samba.samba3 import libsmb_samba_internal as libsmb
|
|
from samba.credentials import SMB_SIGNING_REQUIRED
|
|
|
|
class smb_pipe_socket(object):
|
|
|
|
def __init__(self, target_hostname, pipename, creds, impersonation_level, lp):
|
|
lp3 = s3param.get_context()
|
|
lp3.load(lp.configfile)
|
|
saved_signing_state = creds.get_smb_ipc_signing()
|
|
creds.set_smb_ipc_signing(SMB_SIGNING_REQUIRED)
|
|
self.smbconn = libsmb.Conn(target_hostname, 'IPC$', lp3,
|
|
creds=creds, ipc=True)
|
|
creds.set_smb_ipc_signing(saved_signing_state)
|
|
self.smbfid = self.smbconn.create(pipename,
|
|
DesiredAccess=0x12019f,
|
|
ShareAccess=0x7,
|
|
CreateDisposition=1,
|
|
CreateOptions=0x400040,
|
|
ImpersonationLevel=impersonation_level)
|
|
return
|
|
|
|
def close(self):
|
|
self.smbconn.close(self.smbfid)
|
|
del self.smbconn
|
|
|
|
def settimeout(self, timeo):
|
|
# The socket module we simulate there
|
|
# specifies the timeo as seconds as float.
|
|
msecs = int(timeo * 1000)
|
|
assert msecs >= 0
|
|
self.smbconn.settimeout(msecs)
|
|
return
|
|
|
|
def send(self, buf, flags=0):
|
|
return self.smbconn.write(self.smbfid, buffer=buf, offset=0, mode=8)
|
|
|
|
def recv(self, len, flags=0):
|
|
try:
|
|
return self.smbconn.read(self.smbfid, offset=0, size=len)
|
|
except NTSTATUSError as e:
|
|
if e.args[0] == NT_STATUS_CONNECTION_DISCONNECTED:
|
|
return b'\0' * 0
|
|
if e.args[0] == NT_STATUS_PIPE_DISCONNECTED:
|
|
return b'\0' * 0
|
|
if e.args[0] == NT_STATUS_IO_TIMEOUT:
|
|
raise socket.timeout(str(e))
|
|
raise e
|
|
|
|
class RawDCERPCTest(TestCase):
|
|
"""A raw DCE/RPC Test case."""
|
|
|
|
def _disconnect(self, reason):
|
|
if self.s is None:
|
|
return
|
|
self.s.close()
|
|
self.s = None
|
|
if self.do_hexdump:
|
|
sys.stderr.write("disconnect[%s]\n" % reason)
|
|
|
|
def _connect_tcp(self):
|
|
tcp_port = int(self.primary_address)
|
|
try:
|
|
self.a = socket.getaddrinfo(self.host, tcp_port, socket.AF_UNSPEC,
|
|
socket.SOCK_STREAM, socket.SOL_TCP,
|
|
0)
|
|
self.s = socket.socket(self.a[0][0], self.a[0][1], self.a[0][2])
|
|
self.s.settimeout(10)
|
|
self.s.connect(self.a[0][4])
|
|
except socket.error as e:
|
|
self.s.close()
|
|
raise
|
|
except IOError as e:
|
|
self.s.close()
|
|
raise
|
|
except Exception as e:
|
|
raise
|
|
finally:
|
|
pass
|
|
self.max_xmit_frag = 5840
|
|
self.max_recv_frag = 5840
|
|
if self.secondary_address is None:
|
|
self.secondary_address = self.primary_address
|
|
# compat for older tests
|
|
self.tcp_port = tcp_port
|
|
|
|
def _connect_smb(self):
|
|
a = self.primary_address.split('\\')
|
|
self.assertEqual(len(a), 3)
|
|
self.assertEqual(a[0], "")
|
|
self.assertEqual(a[1], "pipe")
|
|
pipename = a[2]
|
|
self.s = smb_pipe_socket(self.target_hostname,
|
|
pipename,
|
|
self.transport_creds,
|
|
self.transport_impersonation,
|
|
self.lp_ctx)
|
|
self.max_xmit_frag = 4280
|
|
self.max_recv_frag = 4280
|
|
if self.secondary_address is None:
|
|
self.secondary_address = self.primary_address
|
|
|
|
def connect(self):
|
|
self.assertNotConnected()
|
|
if self.primary_address.startswith("\\pipe\\"):
|
|
self._connect_smb()
|
|
else:
|
|
self._connect_tcp()
|
|
if self.secondary_address is None:
|
|
self.secondary_address = self.primary_address
|
|
return
|
|
|
|
def setUp(self):
|
|
super(RawDCERPCTest, self).setUp()
|
|
self.do_ndr_print = False
|
|
self.do_hexdump = False
|
|
|
|
self.ignore_random_pad = samba.tests.env_get_var_value('IGNORE_RANDOM_PAD',
|
|
allow_missing=True)
|
|
self.host = samba.tests.env_get_var_value('SERVER')
|
|
self.target_hostname = samba.tests.env_get_var_value('TARGET_HOSTNAME', allow_missing=True)
|
|
if self.target_hostname is None:
|
|
self.target_hostname = self.host
|
|
self.primary_address = "135"
|
|
self.secondary_address = None
|
|
self.transport_creds = self.get_anon_creds()
|
|
self.transport_impersonation = 0x2
|
|
|
|
self.settings = {}
|
|
self.settings["lp_ctx"] = self.lp_ctx = samba.tests.env_loadparm()
|
|
self.settings["target_hostname"] = self.target_hostname
|
|
|
|
self.s = None
|
|
self.connect()
|
|
|
|
def tearDown(self):
|
|
self._disconnect("tearDown")
|
|
super(TestCase, self).tearDown()
|
|
|
|
def noop(self):
|
|
return
|
|
|
|
def reconnect_smb_pipe(self, primary_address, secondary_address=None,
|
|
transport_creds=None, transport_impersonation=None):
|
|
self._disconnect("reconnect_smb_pipe")
|
|
self.assertIsNotNone(primary_address)
|
|
self.primary_address = primary_address
|
|
if secondary_address is not None:
|
|
self.secondary_address = secondary_address
|
|
else:
|
|
self.secondary_address = None
|
|
|
|
if transport_creds is not None:
|
|
self.transport_creds = transport_creds
|
|
|
|
if transport_impersonation is not None:
|
|
self.transport_impersonation = transport_impersonation
|
|
|
|
self.connect()
|
|
return
|
|
|
|
def second_connection(self, primary_address=None, secondary_address=None,
|
|
transport_creds=None, transport_impersonation=None):
|
|
c = RawDCERPCTest(methodName='noop')
|
|
c.do_ndr_print = self.do_ndr_print
|
|
c.do_hexdump = self.do_hexdump
|
|
c.ignore_random_pad = self.ignore_random_pad
|
|
|
|
c.host = self.host
|
|
c.target_hostname = self.target_hostname
|
|
if primary_address is not None:
|
|
c.primary_address = primary_address
|
|
if secondary_address is not None:
|
|
c.secondary_address = secondary_address
|
|
else:
|
|
c.secondary_address = None
|
|
else:
|
|
self.assertIsNone(secondary_address)
|
|
c.primary_address = self.primary_address
|
|
c.secondary_address = self.secondary_address
|
|
|
|
if transport_creds is not None:
|
|
c.transport_creds = transport_creds
|
|
else:
|
|
c.transport_creds = self.transport_creds
|
|
|
|
if transport_impersonation is not None:
|
|
c.transport_impersonation = transport_impersonation
|
|
else:
|
|
c.transport_impersonation = self.transport_impersonation
|
|
|
|
c.lp_ctx = self.lp_ctx
|
|
c.settings = self.settings
|
|
|
|
c.s = None
|
|
c.connect()
|
|
return c
|
|
|
|
def get_user_creds(self):
|
|
c = Credentials()
|
|
c.guess()
|
|
domain = samba.tests.env_get_var_value('DOMAIN')
|
|
realm = samba.tests.env_get_var_value('REALM')
|
|
username = samba.tests.env_get_var_value('USERNAME')
|
|
password = samba.tests.env_get_var_value('PASSWORD')
|
|
c.set_domain(domain)
|
|
c.set_realm(realm)
|
|
c.set_username(username)
|
|
c.set_password(password)
|
|
return c
|
|
|
|
def get_anon_creds(self):
|
|
c = Credentials()
|
|
c.set_anonymous()
|
|
return c
|
|
|
|
def get_auth_context_creds(self, creds, auth_type, auth_level,
|
|
auth_context_id,
|
|
g_auth_level=None,
|
|
hdr_signing=False):
|
|
|
|
if g_auth_level is None:
|
|
g_auth_level = auth_level
|
|
|
|
g = gensec.Security.start_client(self.settings)
|
|
g.set_credentials(creds)
|
|
g.want_feature(gensec.FEATURE_DCE_STYLE)
|
|
g.start_mech_by_authtype(auth_type, g_auth_level)
|
|
|
|
if auth_type == dcerpc.DCERPC_AUTH_TYPE_KRB5:
|
|
expect_3legs = True
|
|
elif auth_type == dcerpc.DCERPC_AUTH_TYPE_NTLMSSP:
|
|
expect_3legs = True
|
|
else:
|
|
expect_3legs = False
|
|
|
|
auth_context = {}
|
|
auth_context["auth_type"] = auth_type
|
|
auth_context["auth_level"] = auth_level
|
|
auth_context["auth_context_id"] = auth_context_id
|
|
auth_context["g_auth_level"] = g_auth_level
|
|
auth_context["gensec"] = g
|
|
auth_context["hdr_signing"] = hdr_signing
|
|
auth_context["expect_3legs"] = expect_3legs
|
|
|
|
return auth_context
|
|
|
|
def do_generic_bind(self, ctx, auth_context=None,
|
|
pfc_flags=samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
|
|
samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST,
|
|
assoc_group_id=0, call_id=0,
|
|
nak_reason=None, alter_fault=None,
|
|
start_with_alter=False,
|
|
pfc_flags_2nd=samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
|
|
samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST,
|
|
use_auth3=False):
|
|
ctx_list = [ctx]
|
|
|
|
if auth_context is not None:
|
|
if auth_context['hdr_signing']:
|
|
pfc_flags |= dcerpc.DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
|
|
|
|
expect_3legs = auth_context["expect_3legs"]
|
|
|
|
from_server = b""
|
|
(finished, to_server) = auth_context["gensec"].update(from_server)
|
|
self.assertFalse(finished)
|
|
|
|
auth_info = self.generate_auth(auth_type=auth_context["auth_type"],
|
|
auth_level=auth_context["auth_level"],
|
|
auth_context_id=auth_context["auth_context_id"],
|
|
auth_blob=to_server)
|
|
else:
|
|
auth_info = b""
|
|
|
|
if start_with_alter:
|
|
req = self.generate_alter(call_id=call_id,
|
|
pfc_flags=pfc_flags,
|
|
ctx_list=ctx_list,
|
|
assoc_group_id=0xffffffff - assoc_group_id,
|
|
auth_info=auth_info)
|
|
self.send_pdu(req)
|
|
rep = self.recv_pdu()
|
|
if alter_fault is not None:
|
|
self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_FAULT, req.call_id,
|
|
pfc_flags=req.pfc_flags |
|
|
samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
|
|
auth_length=0)
|
|
self.assertNotEqual(rep.u.alloc_hint, 0)
|
|
self.assertEqual(rep.u.context_id, 0)
|
|
self.assertEqual(rep.u.cancel_count, 0)
|
|
self.assertEqual(rep.u.flags, 0)
|
|
self.assertEqual(rep.u.status, alter_fault)
|
|
self.assertEqual(rep.u.reserved, 0)
|
|
self.assertEqual(len(rep.u.error_and_verifier), 0)
|
|
return None
|
|
self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
|
|
pfc_flags=req.pfc_flags)
|
|
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
|
|
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
|
|
self.assertEqual(rep.u.assoc_group_id, assoc_group_id)
|
|
self.assertEqual(rep.u.secondary_address_size, 0)
|
|
self.assertEqual(rep.u.secondary_address, '')
|
|
self.assertPadding(rep.u._pad1, 2)
|
|
else:
|
|
req = self.generate_bind(call_id=call_id,
|
|
pfc_flags=pfc_flags,
|
|
ctx_list=ctx_list,
|
|
assoc_group_id=assoc_group_id,
|
|
auth_info=auth_info)
|
|
self.send_pdu(req)
|
|
rep = self.recv_pdu()
|
|
if nak_reason is not None:
|
|
self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_BIND_NAK, req.call_id,
|
|
auth_length=0)
|
|
self.assertEqual(rep.u.reject_reason, nak_reason)
|
|
self.assertEqual(rep.u.num_versions, 1)
|
|
self.assertEqual(rep.u.versions[0].rpc_vers, req.rpc_vers)
|
|
self.assertEqual(rep.u.versions[0].rpc_vers_minor, req.rpc_vers_minor)
|
|
self.assertPadding(rep.u._pad, 3)
|
|
return
|
|
self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_BIND_ACK, req.call_id,
|
|
pfc_flags=pfc_flags)
|
|
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
|
|
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
|
|
if assoc_group_id != 0:
|
|
self.assertEqual(rep.u.assoc_group_id, assoc_group_id)
|
|
else:
|
|
self.assertNotEqual(rep.u.assoc_group_id, 0)
|
|
assoc_group_id = rep.u.assoc_group_id
|
|
sda_str = self.secondary_address
|
|
sda_len = len(sda_str) + 1
|
|
mod_len = (2 + sda_len) % 4
|
|
if mod_len != 0:
|
|
sda_pad = 4 - mod_len
|
|
else:
|
|
sda_pad = 0
|
|
self.assertEqual(rep.u.secondary_address_size, sda_len)
|
|
self.assertEqual(rep.u.secondary_address, sda_str)
|
|
self.assertPadding(rep.u._pad1, sda_pad)
|
|
|
|
self.assertEqual(rep.u.num_results, 1)
|
|
self.assertEqual(rep.u.ctx_list[0].result,
|
|
samba.dcerpc.dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
|
|
self.assertEqual(rep.u.ctx_list[0].reason,
|
|
samba.dcerpc.dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
|
|
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ctx.transfer_syntaxes[0])
|
|
ack = rep
|
|
if auth_context is None:
|
|
self.assertEqual(rep.auth_length, 0)
|
|
self.assertEqual(len(rep.u.auth_info), 0)
|
|
return ack
|
|
self.assertNotEqual(rep.auth_length, 0)
|
|
self.assertGreater(len(rep.u.auth_info), samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH)
|
|
self.assertEqual(rep.auth_length, len(rep.u.auth_info) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH)
|
|
|
|
a = self.parse_auth(rep.u.auth_info, auth_context=auth_context)
|
|
|
|
from_server = a.credentials
|
|
(finished, to_server) = auth_context["gensec"].update(from_server)
|
|
if expect_3legs:
|
|
self.assertTrue(finished)
|
|
if auth_context['hdr_signing']:
|
|
auth_context["gensec"].want_feature(gensec.FEATURE_SIGN_PKT_HEADER)
|
|
else:
|
|
self.assertFalse(use_auth3)
|
|
self.assertFalse(finished)
|
|
|
|
auth_info = self.generate_auth(auth_type=auth_context["auth_type"],
|
|
auth_level=auth_context["auth_level"],
|
|
auth_context_id=auth_context["auth_context_id"],
|
|
auth_blob=to_server)
|
|
if use_auth3:
|
|
req = self.generate_auth3(call_id=call_id,
|
|
pfc_flags=pfc_flags_2nd,
|
|
auth_info=auth_info)
|
|
self.send_pdu(req)
|
|
rep = self.recv_pdu(timeout=0.01)
|
|
self.assertIsNone(rep)
|
|
self.assertIsConnected()
|
|
return ack
|
|
req = self.generate_alter(call_id=call_id,
|
|
ctx_list=ctx_list,
|
|
pfc_flags=pfc_flags_2nd,
|
|
assoc_group_id=0xffffffff - assoc_group_id,
|
|
auth_info=auth_info)
|
|
self.send_pdu(req)
|
|
rep = self.recv_pdu()
|
|
if alter_fault is not None:
|
|
self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_FAULT, req.call_id,
|
|
pfc_flags=req.pfc_flags |
|
|
samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
|
|
auth_length=0)
|
|
self.assertNotEqual(rep.u.alloc_hint, 0)
|
|
self.assertEqual(rep.u.context_id, 0)
|
|
self.assertEqual(rep.u.cancel_count, 0)
|
|
self.assertEqual(rep.u.flags, 0)
|
|
self.assertEqual(rep.u.status, alter_fault)
|
|
self.assertEqual(rep.u.reserved, 0)
|
|
self.assertEqual(len(rep.u.error_and_verifier), 0)
|
|
return None
|
|
self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_ALTER_RESP, req.call_id,
|
|
pfc_flags=req.pfc_flags)
|
|
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
|
|
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
|
|
self.assertEqual(rep.u.assoc_group_id, assoc_group_id)
|
|
self.assertEqual(rep.u.secondary_address_size, 0)
|
|
self.assertEqual(rep.u.secondary_address, '')
|
|
self.assertPadding(rep.u._pad1, 2)
|
|
self.assertEqual(rep.u.num_results, 1)
|
|
self.assertEqual(rep.u.ctx_list[0].result,
|
|
samba.dcerpc.dcerpc.DCERPC_BIND_ACK_RESULT_ACCEPTANCE)
|
|
self.assertEqual(rep.u.ctx_list[0].reason,
|
|
samba.dcerpc.dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
|
|
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ctx.transfer_syntaxes[0])
|
|
if finished:
|
|
self.assertEqual(rep.auth_length, 0)
|
|
else:
|
|
self.assertNotEqual(rep.auth_length, 0)
|
|
self.assertGreaterEqual(len(rep.u.auth_info), samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH)
|
|
self.assertEqual(rep.auth_length, len(rep.u.auth_info) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH)
|
|
|
|
a = self.parse_auth(rep.u.auth_info, auth_context=auth_context)
|
|
|
|
if finished:
|
|
return ack
|
|
|
|
from_server = a.credentials
|
|
(finished, to_server) = auth_context["gensec"].update(from_server)
|
|
self.assertTrue(finished)
|
|
if auth_context['hdr_signing']:
|
|
auth_context["gensec"].want_feature(gensec.FEATURE_SIGN_PKT_HEADER)
|
|
|
|
return ack
|
|
|
|
def prepare_presentation(self, abstract, transfer, object=None,
|
|
context_id=0xffff, epmap=False, auth_context=None,
|
|
pfc_flags=samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
|
|
samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST,
|
|
assoc_group_id=0,
|
|
return_ack=False):
|
|
if epmap:
|
|
self.epmap_reconnect(abstract, transfer=transfer, object=object)
|
|
|
|
tsf1_list = [transfer]
|
|
ctx = samba.dcerpc.dcerpc.ctx_list()
|
|
ctx.context_id = context_id
|
|
ctx.num_transfer_syntaxes = len(tsf1_list)
|
|
ctx.abstract_syntax = abstract
|
|
ctx.transfer_syntaxes = tsf1_list
|
|
|
|
ack = self.do_generic_bind(ctx=ctx,
|
|
auth_context=auth_context,
|
|
pfc_flags=pfc_flags,
|
|
assoc_group_id=assoc_group_id)
|
|
if ack is None:
|
|
ctx = None
|
|
|
|
if return_ack:
|
|
return (ctx, ack)
|
|
return ctx
|
|
|
|
def do_single_request(self, call_id, ctx, io,
|
|
auth_context=None,
|
|
object=None,
|
|
bigendian=False, ndr64=False,
|
|
allow_remaining=False,
|
|
send_req=True,
|
|
recv_rep=True,
|
|
fault_pfc_flags=(
|
|
samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
|
|
samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
|
|
fault_status=None,
|
|
fault_context_id=None,
|
|
timeout=None,
|
|
ndr_print=None,
|
|
hexdump=None):
|
|
|
|
if fault_context_id is None:
|
|
fault_context_id = ctx.context_id
|
|
|
|
if ndr_print is None:
|
|
ndr_print = self.do_ndr_print
|
|
if hexdump is None:
|
|
hexdump = self.do_hexdump
|
|
|
|
if send_req:
|
|
if ndr_print:
|
|
sys.stderr.write("in: %s" % samba.ndr.ndr_print_in(io))
|
|
stub_in = samba.ndr.ndr_pack_in(io, bigendian=bigendian, ndr64=ndr64)
|
|
if hexdump:
|
|
sys.stderr.write("stub_in: %d\n%s" % (len(stub_in), self.hexdump(stub_in)))
|
|
|
|
pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST
|
|
pfc_flags |= samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST
|
|
if object is not None:
|
|
pfc_flags |= samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_OBJECT_UUID
|
|
|
|
req = self.generate_request_auth(call_id=call_id,
|
|
context_id=ctx.context_id,
|
|
pfc_flags=pfc_flags,
|
|
object=object,
|
|
opnum=io.opnum(),
|
|
stub=stub_in,
|
|
auth_context=auth_context)
|
|
self.send_pdu(req, ndr_print=ndr_print, hexdump=hexdump)
|
|
if recv_rep:
|
|
(rep, rep_blob) = self.recv_pdu_raw(timeout=timeout,
|
|
ndr_print=ndr_print,
|
|
hexdump=hexdump)
|
|
if fault_status:
|
|
self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_FAULT, call_id,
|
|
pfc_flags=fault_pfc_flags, auth_length=0)
|
|
self.assertNotEqual(rep.u.alloc_hint, 0)
|
|
self.assertEqual(rep.u.context_id, fault_context_id)
|
|
self.assertEqual(rep.u.cancel_count, 0)
|
|
self.assertEqual(rep.u.flags, 0)
|
|
self.assertEqual(rep.u.status, fault_status)
|
|
self.assertEqual(rep.u.reserved, 0)
|
|
self.assertEqual(len(rep.u.error_and_verifier), 0)
|
|
return
|
|
|
|
expected_auth_length = 0
|
|
if auth_context is not None and \
|
|
auth_context["auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PACKET:
|
|
if send_req:
|
|
expected_auth_length = req.auth_length
|
|
else:
|
|
expected_auth_length = rep.auth_length
|
|
|
|
|
|
self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_RESPONSE, call_id,
|
|
auth_length=expected_auth_length)
|
|
self.assertNotEqual(rep.u.alloc_hint, 0)
|
|
self.assertEqual(rep.u.context_id, ctx.context_id & 0xff)
|
|
self.assertEqual(rep.u.cancel_count, 0)
|
|
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
|
|
stub_out = self.check_response_auth(rep, rep_blob, auth_context)
|
|
self.assertEqual(len(stub_out), rep.u.alloc_hint)
|
|
|
|
if hexdump:
|
|
sys.stderr.write("stub_out: %d\n%s" % (len(stub_out), self.hexdump(stub_out)))
|
|
ndr_unpack_out(io, stub_out, bigendian=bigendian, ndr64=ndr64,
|
|
allow_remaining=allow_remaining)
|
|
if ndr_print:
|
|
sys.stderr.write("out: %s" % samba.ndr.ndr_print_out(io))
|
|
|
|
def epmap_reconnect(self, abstract, transfer=None, object=None):
|
|
ndr32 = samba.dcerpc.base.transfer_syntax_ndr()
|
|
|
|
if transfer is None:
|
|
transfer = ndr32
|
|
|
|
if object is None:
|
|
object = samba.dcerpc.misc.GUID()
|
|
|
|
ctx = self.prepare_presentation(samba.dcerpc.epmapper.abstract_syntax(),
|
|
transfer, context_id=0)
|
|
|
|
data1 = ndr_pack(abstract)
|
|
lhs1 = samba.dcerpc.epmapper.epm_lhs()
|
|
lhs1.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_UUID
|
|
lhs1.lhs_data = data1[:18]
|
|
rhs1 = samba.dcerpc.epmapper.epm_rhs_uuid()
|
|
rhs1.unknown = data1[18:]
|
|
floor1 = samba.dcerpc.epmapper.epm_floor()
|
|
floor1.lhs = lhs1
|
|
floor1.rhs = rhs1
|
|
data2 = ndr_pack(transfer)
|
|
lhs2 = samba.dcerpc.epmapper.epm_lhs()
|
|
lhs2.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_UUID
|
|
lhs2.lhs_data = data2[:18]
|
|
rhs2 = samba.dcerpc.epmapper.epm_rhs_uuid()
|
|
rhs2.unknown = data1[18:]
|
|
floor2 = samba.dcerpc.epmapper.epm_floor()
|
|
floor2.lhs = lhs2
|
|
floor2.rhs = rhs2
|
|
lhs3 = samba.dcerpc.epmapper.epm_lhs()
|
|
lhs3.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_NCACN
|
|
lhs3.lhs_data = b""
|
|
floor3 = samba.dcerpc.epmapper.epm_floor()
|
|
floor3.lhs = lhs3
|
|
floor3.rhs.minor_version = 0
|
|
lhs4 = samba.dcerpc.epmapper.epm_lhs()
|
|
lhs4.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_TCP
|
|
lhs4.lhs_data = b""
|
|
floor4 = samba.dcerpc.epmapper.epm_floor()
|
|
floor4.lhs = lhs4
|
|
floor4.rhs.port = int(self.primary_address)
|
|
lhs5 = samba.dcerpc.epmapper.epm_lhs()
|
|
lhs5.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_IP
|
|
lhs5.lhs_data = b""
|
|
floor5 = samba.dcerpc.epmapper.epm_floor()
|
|
floor5.lhs = lhs5
|
|
floor5.rhs.ipaddr = "0.0.0.0"
|
|
|
|
floors = [floor1, floor2, floor3, floor4, floor5]
|
|
req_tower = samba.dcerpc.epmapper.epm_tower()
|
|
req_tower.num_floors = len(floors)
|
|
req_tower.floors = floors
|
|
req_twr = samba.dcerpc.epmapper.epm_twr_t()
|
|
req_twr.tower = req_tower
|
|
|
|
epm_map = samba.dcerpc.epmapper.epm_Map()
|
|
epm_map.in_object = object
|
|
epm_map.in_map_tower = req_twr
|
|
epm_map.in_entry_handle = samba.dcerpc.misc.policy_handle()
|
|
epm_map.in_max_towers = 4
|
|
|
|
self.do_single_request(call_id=2, ctx=ctx, io=epm_map)
|
|
|
|
self.assertGreaterEqual(epm_map.out_num_towers, 1)
|
|
rep_twr = epm_map.out_towers[0].twr
|
|
self.assertIsNotNone(rep_twr)
|
|
self.assertEqual(rep_twr.tower_length, 75)
|
|
self.assertEqual(rep_twr.tower.num_floors, 5)
|
|
self.assertEqual(len(rep_twr.tower.floors), 5)
|
|
self.assertEqual(rep_twr.tower.floors[3].lhs.protocol,
|
|
samba.dcerpc.epmapper.EPM_PROTOCOL_TCP)
|
|
self.assertEqual(rep_twr.tower.floors[3].lhs.protocol,
|
|
samba.dcerpc.epmapper.EPM_PROTOCOL_TCP)
|
|
|
|
# reconnect to the given port
|
|
self._disconnect("epmap_reconnect")
|
|
self.primary_address = "%d" % rep_twr.tower.floors[3].rhs.port
|
|
self.secondary_address = None
|
|
self.connect()
|
|
|
|
def send_pdu(self, req, ndr_print=None, hexdump=None):
|
|
if ndr_print is None:
|
|
ndr_print = self.do_ndr_print
|
|
if hexdump is None:
|
|
hexdump = self.do_hexdump
|
|
try:
|
|
req_pdu = ndr_pack(req)
|
|
if ndr_print:
|
|
sys.stderr.write("send_pdu: %s" % samba.ndr.ndr_print(req))
|
|
if hexdump:
|
|
sys.stderr.write("send_pdu: %d\n%s" % (len(req_pdu), self.hexdump(req_pdu)))
|
|
while True:
|
|
sent = self.s.send(req_pdu, 0)
|
|
if sent == len(req_pdu):
|
|
break
|
|
req_pdu = req_pdu[sent:]
|
|
except socket.error as e:
|
|
self._disconnect("send_pdu: %s" % e)
|
|
raise
|
|
except IOError as e:
|
|
self._disconnect("send_pdu: %s" % e)
|
|
raise
|
|
except NTSTATUSError as e:
|
|
self._disconnect("send_pdu: %s" % e)
|
|
raise
|
|
finally:
|
|
pass
|
|
|
|
def recv_raw(self, hexdump=None, timeout=None):
|
|
rep_pdu = None
|
|
if hexdump is None:
|
|
hexdump = self.do_hexdump
|
|
try:
|
|
if timeout is not None:
|
|
self.s.settimeout(timeout)
|
|
rep_pdu = self.s.recv(0xffff, 0)
|
|
self.s.settimeout(10)
|
|
if len(rep_pdu) == 0:
|
|
self._disconnect("recv_raw: EOF")
|
|
return None
|
|
if hexdump:
|
|
sys.stderr.write("recv_raw: %d\n%s" % (len(rep_pdu), self.hexdump(rep_pdu)))
|
|
except socket.timeout as e:
|
|
self.s.settimeout(10)
|
|
sys.stderr.write("recv_raw: TIMEOUT\n")
|
|
pass
|
|
except socket.error as e:
|
|
self._disconnect("recv_raw: %s" % e)
|
|
raise
|
|
except IOError as e:
|
|
self._disconnect("recv_raw: %s" % e)
|
|
raise
|
|
finally:
|
|
pass
|
|
return rep_pdu
|
|
|
|
def recv_pdu_raw(self, ndr_print=None, hexdump=None, timeout=None):
|
|
rep_pdu = None
|
|
rep = None
|
|
if ndr_print is None:
|
|
ndr_print = self.do_ndr_print
|
|
if hexdump is None:
|
|
hexdump = self.do_hexdump
|
|
try:
|
|
rep_pdu = self.recv_raw(hexdump=hexdump, timeout=timeout)
|
|
if rep_pdu is None:
|
|
return (None, None)
|
|
rep = ndr_unpack(samba.dcerpc.dcerpc.ncacn_packet, rep_pdu, allow_remaining=True)
|
|
if ndr_print:
|
|
sys.stderr.write("recv_pdu: %s" % samba.ndr.ndr_print(rep))
|
|
self.assertEqual(rep.frag_length, len(rep_pdu))
|
|
finally:
|
|
pass
|
|
return (rep, rep_pdu)
|
|
|
|
def recv_pdu(self, ndr_print=None, hexdump=None, timeout=None):
|
|
(rep, rep_pdu) = self.recv_pdu_raw(ndr_print=ndr_print,
|
|
hexdump=hexdump,
|
|
timeout=timeout)
|
|
return rep
|
|
|
|
def generate_auth(self,
|
|
auth_type=None,
|
|
auth_level=None,
|
|
auth_pad_length=0,
|
|
auth_context_id=None,
|
|
auth_blob=None,
|
|
ndr_print=None, hexdump=None):
|
|
if ndr_print is None:
|
|
ndr_print = self.do_ndr_print
|
|
if hexdump is None:
|
|
hexdump = self.do_hexdump
|
|
|
|
if auth_type is not None:
|
|
a = samba.dcerpc.dcerpc.auth()
|
|
a.auth_type = auth_type
|
|
a.auth_level = auth_level
|
|
a.auth_pad_length = auth_pad_length
|
|
a.auth_context_id = auth_context_id
|
|
a.credentials = auth_blob
|
|
|
|
ai = ndr_pack(a)
|
|
if ndr_print:
|
|
sys.stderr.write("generate_auth: %s" % samba.ndr.ndr_print(a))
|
|
if hexdump:
|
|
sys.stderr.write("generate_auth: %d\n%s" % (len(ai), self.hexdump(ai)))
|
|
else:
|
|
ai = b""
|
|
|
|
return ai
|
|
|
|
def parse_auth(self, auth_info, ndr_print=None, hexdump=None,
|
|
auth_context=None, stub_len=0):
|
|
if ndr_print is None:
|
|
ndr_print = self.do_ndr_print
|
|
if hexdump is None:
|
|
hexdump = self.do_hexdump
|
|
|
|
if (len(auth_info) <= samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH):
|
|
return None
|
|
|
|
if hexdump:
|
|
sys.stderr.write("parse_auth: %d\n%s" % (len(auth_info), self.hexdump(auth_info)))
|
|
a = ndr_unpack(samba.dcerpc.dcerpc.auth, auth_info, allow_remaining=True)
|
|
if ndr_print:
|
|
sys.stderr.write("parse_auth: %s" % samba.ndr.ndr_print(a))
|
|
|
|
if auth_context is not None:
|
|
self.assertEqual(a.auth_type, auth_context["auth_type"])
|
|
self.assertEqual(a.auth_level, auth_context["auth_level"])
|
|
self.assertEqual(a.auth_reserved, 0)
|
|
self.assertEqual(a.auth_context_id, auth_context["auth_context_id"])
|
|
|
|
self.assertLessEqual(a.auth_pad_length, dcerpc.DCERPC_AUTH_PAD_ALIGNMENT)
|
|
self.assertLessEqual(a.auth_pad_length, stub_len)
|
|
|
|
return a
|
|
|
|
def check_response_auth(self, rep, rep_blob, auth_context=None,
|
|
auth_pad_length=None):
|
|
|
|
if auth_context is None:
|
|
self.assertEqual(rep.auth_length, 0)
|
|
return rep.u.stub_and_verifier
|
|
|
|
if auth_context["auth_level"] == dcerpc.DCERPC_AUTH_LEVEL_CONNECT:
|
|
self.assertEqual(rep.auth_length, 0)
|
|
return rep.u.stub_and_verifier
|
|
|
|
self.assertGreater(rep.auth_length, 0)
|
|
|
|
ofs_stub = dcerpc.DCERPC_REQUEST_LENGTH
|
|
ofs_sig = rep.frag_length - rep.auth_length
|
|
ofs_trailer = ofs_sig - dcerpc.DCERPC_AUTH_TRAILER_LENGTH
|
|
rep_data = rep_blob[ofs_stub:ofs_trailer]
|
|
rep_whole = rep_blob[0:ofs_sig]
|
|
rep_sig = rep_blob[ofs_sig:]
|
|
rep_auth_info_blob = rep_blob[ofs_trailer:]
|
|
|
|
rep_auth_info = self.parse_auth(rep_auth_info_blob,
|
|
auth_context=auth_context,
|
|
stub_len=len(rep_data))
|
|
if auth_pad_length is not None:
|
|
self.assertEqual(rep_auth_info.auth_pad_length, auth_pad_length)
|
|
self.assertEqual(rep_auth_info.credentials, rep_sig)
|
|
|
|
if auth_context["auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PRIVACY:
|
|
# TODO: not yet supported here
|
|
self.assertTrue(False)
|
|
elif auth_context["auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PACKET:
|
|
auth_context["gensec"].check_packet(rep_data, rep_whole, rep_sig)
|
|
|
|
stub_out = rep_data[0:len(rep_data)-rep_auth_info.auth_pad_length]
|
|
|
|
return stub_out
|
|
|
|
def generate_pdu(self, ptype, call_id, payload,
|
|
rpc_vers=5,
|
|
rpc_vers_minor=0,
|
|
pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
|
|
samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
|
|
drep=None,
|
|
ndr_print=None, hexdump=None):
|
|
|
|
if drep is None:
|
|
drep = [samba.dcerpc.dcerpc.DCERPC_DREP_LE, 0, 0, 0]
|
|
if getattr(payload, 'auth_info', None):
|
|
ai = payload.auth_info
|
|
else:
|
|
ai = b""
|
|
|
|
p = samba.dcerpc.dcerpc.ncacn_packet()
|
|
p.rpc_vers = rpc_vers
|
|
p.rpc_vers_minor = rpc_vers_minor
|
|
p.ptype = ptype
|
|
p.pfc_flags = pfc_flags
|
|
p.drep = drep
|
|
p.frag_length = 0
|
|
if len(ai) > samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH:
|
|
p.auth_length = len(ai) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH
|
|
else:
|
|
p.auth_length = 0
|
|
p.call_id = call_id
|
|
p.u = payload
|
|
|
|
pdu = ndr_pack(p)
|
|
p.frag_length = len(pdu)
|
|
|
|
return p
|
|
|
|
def generate_request_auth(self, call_id,
|
|
pfc_flags=(dcerpc.DCERPC_PFC_FLAG_FIRST |
|
|
dcerpc.DCERPC_PFC_FLAG_LAST),
|
|
alloc_hint=None,
|
|
context_id=None,
|
|
opnum=None,
|
|
object=None,
|
|
stub=None,
|
|
auth_context=None,
|
|
ndr_print=None, hexdump=None):
|
|
|
|
if stub is None:
|
|
stub = b""
|
|
|
|
sig_size = 0
|
|
if auth_context is not None:
|
|
mod_len = len(stub) % dcerpc.DCERPC_AUTH_PAD_ALIGNMENT
|
|
auth_pad_length = 0
|
|
if mod_len > 0:
|
|
auth_pad_length = dcerpc.DCERPC_AUTH_PAD_ALIGNMENT - mod_len
|
|
stub += b'\x00' * auth_pad_length
|
|
|
|
if auth_context["g_auth_level"] >= samba.dcerpc.dcerpc.DCERPC_AUTH_LEVEL_PACKET:
|
|
sig_size = auth_context["gensec"].sig_size(len(stub))
|
|
else:
|
|
sig_size = 16
|
|
|
|
zero_sig = b"\x00" * sig_size
|
|
auth_info = self.generate_auth(auth_type=auth_context["auth_type"],
|
|
auth_level=auth_context["auth_level"],
|
|
auth_pad_length=auth_pad_length,
|
|
auth_context_id=auth_context["auth_context_id"],
|
|
auth_blob=zero_sig)
|
|
else:
|
|
auth_info = b""
|
|
|
|
req = self.generate_request(call_id=call_id,
|
|
pfc_flags=pfc_flags,
|
|
alloc_hint=alloc_hint,
|
|
context_id=context_id,
|
|
opnum=opnum,
|
|
object=object,
|
|
stub=stub,
|
|
auth_info=auth_info,
|
|
ndr_print=ndr_print,
|
|
hexdump=hexdump)
|
|
if auth_context is None:
|
|
return req
|
|
|
|
req_blob = samba.ndr.ndr_pack(req)
|
|
ofs_stub = dcerpc.DCERPC_REQUEST_LENGTH
|
|
ofs_sig = len(req_blob) - req.auth_length
|
|
ofs_trailer = ofs_sig - dcerpc.DCERPC_AUTH_TRAILER_LENGTH
|
|
req_data = req_blob[ofs_stub:ofs_trailer]
|
|
req_whole = req_blob[0:ofs_sig]
|
|
|
|
if auth_context["g_auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PRIVACY:
|
|
# TODO: not yet supported here
|
|
self.assertTrue(False)
|
|
elif auth_context["g_auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PACKET:
|
|
req_sig = auth_context["gensec"].sign_packet(req_data, req_whole)
|
|
elif auth_context["g_auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_CONNECT:
|
|
self.assertEqual(auth_context["auth_type"],
|
|
dcerpc.DCERPC_AUTH_TYPE_NTLMSSP)
|
|
req_sig = b"\x01" +b"\x00" *15
|
|
else:
|
|
return req
|
|
self.assertEqual(len(req_sig), req.auth_length)
|
|
self.assertEqual(len(req_sig), sig_size)
|
|
|
|
stub_sig_ofs = len(req.u.stub_and_verifier) - sig_size
|
|
stub = req.u.stub_and_verifier[0:stub_sig_ofs] + req_sig
|
|
req.u.stub_and_verifier = stub
|
|
|
|
return req
|
|
|
|
def verify_pdu(self, p, ptype, call_id,
|
|
rpc_vers=5,
|
|
rpc_vers_minor=0,
|
|
pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
|
|
samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
|
|
drep=None,
|
|
auth_length=None):
|
|
|
|
if drep is None:
|
|
drep = [samba.dcerpc.dcerpc.DCERPC_DREP_LE, 0, 0, 0]
|
|
self.assertIsNotNone(p, "No valid pdu")
|
|
|
|
if getattr(p.u, 'auth_info', None):
|
|
ai = p.u.auth_info
|
|
else:
|
|
ai = b""
|
|
|
|
self.assertEqual(p.rpc_vers, rpc_vers)
|
|
self.assertEqual(p.rpc_vers_minor, rpc_vers_minor)
|
|
self.assertEqual(p.ptype, ptype)
|
|
self.assertEqual(p.pfc_flags, pfc_flags)
|
|
self.assertEqual(p.drep, drep)
|
|
self.assertGreaterEqual(p.frag_length,
|
|
samba.dcerpc.dcerpc.DCERPC_NCACN_PAYLOAD_OFFSET)
|
|
if len(ai) > samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH:
|
|
self.assertEqual(p.auth_length,
|
|
len(ai) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH)
|
|
elif auth_length is not None:
|
|
self.assertEqual(p.auth_length, auth_length)
|
|
else:
|
|
self.assertEqual(p.auth_length, 0)
|
|
self.assertEqual(p.call_id, call_id)
|
|
|
|
return
|
|
|
|
def generate_bind(self, call_id,
|
|
pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
|
|
samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
|
|
max_xmit_frag=None,
|
|
max_recv_frag=None,
|
|
assoc_group_id=0,
|
|
ctx_list=None,
|
|
auth_info=b"",
|
|
ndr_print=None, hexdump=None):
|
|
|
|
if ctx_list is None:
|
|
ctx_list = []
|
|
if max_xmit_frag is None:
|
|
max_xmit_frag=self.max_xmit_frag
|
|
if max_recv_frag is None:
|
|
max_recv_frag=self.max_recv_frag
|
|
|
|
b = samba.dcerpc.dcerpc.bind()
|
|
b.max_xmit_frag = max_xmit_frag
|
|
b.max_recv_frag = max_recv_frag
|
|
b.assoc_group_id = assoc_group_id
|
|
b.num_contexts = len(ctx_list)
|
|
b.ctx_list = ctx_list
|
|
b.auth_info = auth_info
|
|
|
|
p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_BIND,
|
|
pfc_flags=pfc_flags,
|
|
call_id=call_id,
|
|
payload=b,
|
|
ndr_print=ndr_print, hexdump=hexdump)
|
|
|
|
return p
|
|
|
|
def generate_alter(self, call_id,
|
|
pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
|
|
samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
|
|
max_xmit_frag=None,
|
|
max_recv_frag=None,
|
|
assoc_group_id=0,
|
|
ctx_list=None,
|
|
auth_info=b"",
|
|
ndr_print=None, hexdump=None):
|
|
|
|
if ctx_list is None:
|
|
ctx_list = []
|
|
if max_xmit_frag is None:
|
|
max_xmit_frag=self.max_xmit_frag
|
|
if max_recv_frag is None:
|
|
max_recv_frag=self.max_recv_frag
|
|
|
|
a = samba.dcerpc.dcerpc.bind()
|
|
a.max_xmit_frag = max_xmit_frag
|
|
a.max_recv_frag = max_recv_frag
|
|
a.assoc_group_id = assoc_group_id
|
|
a.num_contexts = len(ctx_list)
|
|
a.ctx_list = ctx_list
|
|
a.auth_info = auth_info
|
|
|
|
p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_ALTER,
|
|
pfc_flags=pfc_flags,
|
|
call_id=call_id,
|
|
payload=a,
|
|
ndr_print=ndr_print, hexdump=hexdump)
|
|
|
|
return p
|
|
|
|
def generate_auth3(self, call_id,
|
|
pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
|
|
samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
|
|
auth_info=b"",
|
|
ndr_print=None, hexdump=None):
|
|
|
|
a = samba.dcerpc.dcerpc.auth3()
|
|
a.auth_info = auth_info
|
|
|
|
p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_AUTH3,
|
|
pfc_flags=pfc_flags,
|
|
call_id=call_id,
|
|
payload=a,
|
|
ndr_print=ndr_print, hexdump=hexdump)
|
|
|
|
return p
|
|
|
|
def generate_request(self, call_id,
|
|
pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
|
|
samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
|
|
alloc_hint=None,
|
|
context_id=None,
|
|
opnum=None,
|
|
object=None,
|
|
stub=None,
|
|
auth_info=b"",
|
|
ndr_print=None, hexdump=None):
|
|
|
|
if alloc_hint is None:
|
|
alloc_hint = len(stub)
|
|
|
|
r = samba.dcerpc.dcerpc.request()
|
|
r.alloc_hint = alloc_hint
|
|
r.context_id = context_id
|
|
r.opnum = opnum
|
|
if object is not None:
|
|
r.object = object
|
|
r.stub_and_verifier = stub + auth_info
|
|
|
|
p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_REQUEST,
|
|
pfc_flags=pfc_flags,
|
|
call_id=call_id,
|
|
payload=r,
|
|
ndr_print=ndr_print, hexdump=hexdump)
|
|
|
|
if len(auth_info) > samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH:
|
|
p.auth_length = len(auth_info) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH
|
|
|
|
return p
|
|
|
|
def generate_co_cancel(self, call_id,
|
|
pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
|
|
samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
|
|
auth_info=b"",
|
|
ndr_print=None, hexdump=None):
|
|
|
|
c = samba.dcerpc.dcerpc.co_cancel()
|
|
c.auth_info = auth_info
|
|
|
|
p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_CO_CANCEL,
|
|
pfc_flags=pfc_flags,
|
|
call_id=call_id,
|
|
payload=c,
|
|
ndr_print=ndr_print, hexdump=hexdump)
|
|
|
|
return p
|
|
|
|
def generate_orphaned(self, call_id,
|
|
pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
|
|
samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
|
|
auth_info=b"",
|
|
ndr_print=None, hexdump=None):
|
|
|
|
o = samba.dcerpc.dcerpc.orphaned()
|
|
o.auth_info = auth_info
|
|
|
|
p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_ORPHANED,
|
|
pfc_flags=pfc_flags,
|
|
call_id=call_id,
|
|
payload=o,
|
|
ndr_print=ndr_print, hexdump=hexdump)
|
|
|
|
return p
|
|
|
|
def generate_shutdown(self, call_id,
|
|
pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST |
|
|
samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST),
|
|
ndr_print=None, hexdump=None):
|
|
|
|
s = samba.dcerpc.dcerpc.shutdown()
|
|
|
|
p = self.generate_pdu(ptype=samba.dcerpc.dcerpc.DCERPC_PKT_SHUTDOWN,
|
|
pfc_flags=pfc_flags,
|
|
call_id=call_id,
|
|
payload=s,
|
|
ndr_print=ndr_print, hexdump=hexdump)
|
|
|
|
return p
|
|
|
|
def assertIsConnected(self):
|
|
self.assertIsNotNone(self.s, msg="Not connected")
|
|
return
|
|
|
|
def assertNotConnected(self):
|
|
self.assertIsNone(self.s, msg="Is connected")
|
|
return
|
|
|
|
def assertNDRSyntaxEquals(self, s1, s2):
|
|
self.assertEqual(s1.uuid, s2.uuid)
|
|
self.assertEqual(s1.if_version, s2.if_version)
|
|
return
|
|
|
|
def assertPadding(self, pad, length):
|
|
self.assertEqual(len(pad), length)
|
|
#
|
|
# sometimes windows sends random bytes
|
|
#
|
|
# we have IGNORE_RANDOM_PAD=1 to
|
|
# disable the check
|
|
#
|
|
if self.ignore_random_pad:
|
|
return
|
|
zero_pad = b'\0' * length
|
|
self.assertEqual(pad, zero_pad)
|
|
|
|
def assertEqualsStrLower(self, s1, s2):
|
|
self.assertEqual(str(s1).lower(), str(s2).lower())
|