From 169627d7f55f9f58a6564a9efe659a529bbf348a Mon Sep 17 00:00:00 2001 From: Tim Potter Date: Thu, 23 Sep 2004 02:21:11 +0000 Subject: r2555: Start of a rpcclient type program. (This used to be commit c9d682731226b7ef222f588c43df5a1f62c21555) --- source4/scripting/swig/rpcclient | 154 ++++++++++++++++++++++++++++++++++++ source4/scripting/swig/samr.py | 165 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 319 insertions(+) create mode 100755 source4/scripting/swig/rpcclient create mode 100644 source4/scripting/swig/samr.py diff --git a/source4/scripting/swig/rpcclient b/source4/scripting/swig/rpcclient new file mode 100755 index 0000000000..2a3d12cc8e --- /dev/null +++ b/source4/scripting/swig/rpcclient @@ -0,0 +1,154 @@ +#!/usr/bin/python + +import sys, os, string +from cmd import Cmd +from optparse import OptionParser + + +import dcerpc, samr + +class rpcclient(Cmd): + + prompt = 'rpcclient$ ' + + def __init__(self, binding, domain, username, password): + Cmd.__init__(self) + self.binding = binding + self.domain = domain + self.username = username + self.password = password + + def emptyline(self): + + # Default for empty line is to repeat last command - yuck + + pass + + def onecmd(self, line): + + # Override the onecmd() method so we can trap error returns + + try: + Cmd.onecmd(self, line) + except dcerpc.NTSTATUS, arg: + print 'The command returned an error: %s' % arg[1] + + # Command handlers + + def do_help(self, line): + """Displays on-line help for rpcclient commands.""" + Cmd.do_help(self, line) + + def do_shell(self, line): + + status = os.system(line) + + if os.WIFEXITED(status): + if os.WEXITSTATUS(status) != 0: + print 'Command exited with code %d' % os.WEXITSTATUS(status) + else: + print 'Command exited with signal %d' % os.WTERMSIG(status) + + def do_EOF(self, line): + """Exits rpcclient.""" + print + sys.exit(0) + + # SAMR pipe commands + + def do_SamrEnumDomains(self, line): + """Enumerate domain names.""" + + usage = 'usage: SamrEnumDomains' + + if line != '': + print usage + return + + pipe = dcerpc.pipe_connect( + self.binding, + dcerpc.DCERPC_SAMR_UUID, dcerpc.DCERPC_SAMR_VERSION, + self.domain, self.username, self.password) + + connect_handle = samr.Connect(pipe) + + for i in connect_handle.EnumDomains(): + print i + + def do_SamrLookupDomain(self, line): + """Return the SID for a domain.""" + + usage = 'SamrLookupDomain DOMAIN' + + parser = OptionParser(usage) + options, args = parser.parse_args(string.split(line)) + + if len(args) != 1: + print 'usage:', usage + return + + pipe = dcerpc.pipe_connect( + self.binding, + dcerpc.DCERPC_SAMR_UUID, dcerpc.DCERPC_SAMR_VERSION, + self.domain, self.username, self.password) + + connect_handle = samr.Connect(pipe) + + print connect_handle.LookupDomain(args[0]) + +if __name__ == '__main__': + + # Parse command line + + usage = 'rpcclient BINDING [options]' + + if len(sys.argv) == 1: + print usage + sys.exit(1) + + binding = sys.argv[1] + del(sys.argv[1]) + + if string.find(binding, ':') == -1: + binding = 'ncacn_np:' + binding + + parser = OptionParser(usage) + + parser.add_option('-U', '--username', action='store', type='string', + help='Use given credentials when connecting', + metavar='DOMAIN\\username%password', + dest='username') + + parser.add_option('-c', '--command', action='store', type='string', + help='Execute COMMAND', dest='command') + + options, args = parser.parse_args() + + # Break --username up into domain, usernamd and password + + if not options.username: + options.username = '%' + + domain = '' + if string.find(options.username, '\\') != -1: + domain, options.username = string.split(options.username, '\\') + + password = '' + if string.find(options.username, '%') != -1: + options.username, password = string.split(options.username, '%') + + username = options.username + + # Run command loop + + c = rpcclient(binding, domain, username, password) + + if options.command: + c.onecmd(options.command) + sys.exit(0) + + while 1: + try: + c.cmdloop() + except KeyboardInterrupt: + print 'KeyboardInterrupt' diff --git a/source4/scripting/swig/samr.py b/source4/scripting/swig/samr.py new file mode 100644 index 0000000000..5fd87da3ad --- /dev/null +++ b/source4/scripting/swig/samr.py @@ -0,0 +1,165 @@ +import dcerpc + +def sid_to_string(sid): + """Convert a Python dictionary SID to a string SID.""" + + result = 'S-%d' % sid['sid_rev_num'] + + ia = sid['id_auth'] + + result = result + '-%u' % (ia[5] + (ia[4] << 8) + (ia[3] << 16) + \ + (ia[2] << 24)) + + for i in range(0, sid['num_auths']): + result = result + '-%u' % sid['sub_auths'][i] + + return result + +def string_to_sid(string): + """Convert a string SID to a Python dictionary SID. Throws a + ValueError if the SID string was badly formed.""" + + if string[0] != 'S': + raise ValueError('Bad SID format') + + string = string[1:] + + import re + + match = re.match('-\d+', string) + + if not match: + raise ValueError('Bad SID format') + + try: + sid_rev_num = int(string[match.start()+1:match.end()]) + except ValueError: + raise ValueError('Bad SID format') + + string = string[match.end():] + + match = re.match('-\d+', string) + + if not match: + raise ValueError('Bad SID format') + + try: + ia = int(string[match.start()+1:match.end()]) + except ValueError: + raise ValueError('Bad SID format') + + string = string[match.end():] + + id_auth = [0, 0, (ia >> 24) & 0xff, (ia >> 16) & 0xff, + (ia >> 8) & 0xff, ia & 0xff] + + num_auths = 0 + sub_auths = [] + + while len(string): + + match = re.match('-\d+', string) + + if not match: + raise ValueError('Bad SID format') + + try: + sa = int(string[match.start() + 1 : match.end()]) + except ValueError: + raise ValueError('Bad SID format') + + num_auths = num_auths + 1 + sub_auths.append(int(sa)) + + string = string[match.end():] + + print map(type, sub_auths) + + return {'sid_rev_num': sid_rev_num, 'id_auth': id_auth, + 'num_auths': num_auths, 'sub_auths': sub_auths} + +class SamrHandle: + + def __init__(self, pipe, handle): + + self.pipe = pipe + self.handle = handle + + def __del__(self): + + r = {} + r['handle'] = self.handle + + dcerpc.samr_Close(self.pipe, r) + +class ConnectHandle(SamrHandle): + + def EnumDomains(self): + + r = {} + r['connect_handle'] = self.handle + r['resume_handle'] = 0 + r['buf_size'] = -1 + + domains = [] + + while 1: + + result = dcerpc.samr_EnumDomains(self.pipe, r) + + domains = domains + result['sam']['entries'] + + if result['result'] == dcerpc.STATUS_MORE_ENTRIES: + r['resume_handle'] = result['resume_handle'] + continue + + break + + return map(lambda x: x['name']['name'], domains) + + def LookupDomain(self, domain_name): + + r = {} + r['connect_handle'] = self.handle + r['domain'] = {} + r['domain']['name_len'] = 0 + r['domain']['name_size'] = 0 + r['domain']['name'] = domain_name + + result = dcerpc.samr_LookupDomain(self.pipe, r) + + return sid_to_string(result['sid']) + + def OpenDomain(self, domain_sid, access_mask = 0x02000000): + + r = {} + r['connect_handle'] = self.handle + r['access_mask'] = access_mask + r['sid'] = string_to_sid(domain_sid) + + result = dcerpc.samr_OpenDomain(self.pipe, r) + + return DomainHandle(pipe, result['domain_handle']) + +class DomainHandle(SamrHandle): + + def QueryDomainInfo(self, level = 2): + + r = {} + r['domain_handle'] = self.domain_handle + r['level'] = level + + result = dcerpc.samr_QueryDomainInfo(pipe, r) + + return result + +def Connect(pipe, system_name = None, access_mask = 0x02000000): + """Connect to the SAMR pipe.""" + + r = {} + r['system_name'] = system_name + r['access_mask'] = access_mask + + result = dcerpc.samr_Connect2(pipe, r) + + return ConnectHandle(pipe, result['connect_handle']) -- cgit