summaryrefslogtreecommitdiff
path: root/source4/scripting/bin
diff options
context:
space:
mode:
Diffstat (limited to 'source4/scripting/bin')
-rwxr-xr-xsource4/scripting/bin/autoidl.py161
-rw-r--r--source4/scripting/bin/epdump.py24
-rwxr-xr-xsource4/scripting/bin/minschema.py585
-rwxr-xr-xsource4/scripting/bin/mymachinepw59
-rwxr-xr-xsource4/scripting/bin/rpcclient305
-rwxr-xr-xsource4/scripting/bin/samba3dump167
-rwxr-xr-xsource4/scripting/bin/smbstatus83
-rwxr-xr-xsource4/scripting/bin/subunitrun48
8 files changed, 1432 insertions, 0 deletions
diff --git a/source4/scripting/bin/autoidl.py b/source4/scripting/bin/autoidl.py
new file mode 100755
index 0000000000..eed4ba3a80
--- /dev/null
+++ b/source4/scripting/bin/autoidl.py
@@ -0,0 +1,161 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Unix SMB/CIFS implementation.
+# Copyright © Jelmer Vernooij <jelmer@samba.org> 2008
+#
+# 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
+
+MAX_OPNUM = 1000
+MAX_BASE_SIZE = 0x1000
+MAX_IFACE_VERSION = 1000
+
+DCERPC_FAULT_OP_RNG_ERROR = 0x1c010002
+DCERPC_FAULT_NDR = 0x6f7
+NT_STATUS_NET_WRITE_FAULT = -1073741614
+
+
+sys.path.insert(0, "bin/python")
+
+from samba.dcerpc import ClientConnection
+
+def find_num_funcs(conn):
+ for i in xrange(MAX_OPNUM):
+ try:
+ conn.request(i, "")
+ except RuntimeError, (num, msg):
+ if num == DCERPC_FAULT_OP_RNG_ERROR:
+ return i
+ raise Exception("More than %d functions" % MAX_OPNUM)
+
+class Function:
+ def __init__(self, conn, opnum):
+ self.conn = conn
+ self.opnum = opnum
+
+ def request(self, data):
+ assert isinstance(data, str)
+ self.conn.request(self.opnum, data)
+
+ def valid_ndr(self, data):
+ try:
+ self.request(data)
+ except RuntimeError, (num, msg):
+ if num == DCERPC_FAULT_NDR:
+ return False
+ return True
+
+ def find_base_request(self, start=""):
+ """Find the smallest possible request that we can do that is
+ valid.
+
+ This generally means sending all zeroes so we get NULL pointers where
+ possible."""
+ # TODO: Don't try with just 0's as there may be switch_is() variables
+ # for which 0 is not a valid value or variables with range() set
+ # See how much input bytes we need
+ for i in range(MAX_BASE_SIZE):
+ data = start + chr(0) * i
+ if self.valid_ndr(data):
+ return data
+ return None
+
+ def check_decision_byte(self, base_request, i):
+ """Check whether the specified byte is a possible "decision" byte,
+ e.g. a byte that is part of a pointer, array size variable or
+ discriminant.
+
+ Note that this function only checks if a byte is definitely a decision
+ byte. It may return False in some cases while the byte is actually
+ a decision byte."""
+ data = list(base_request)
+ data[i] = chr(1)
+ return not self.valid_ndr("".join(data))
+
+ def find_deferrant_data(self, base_request, idx):
+ data = list(base_request)
+ data[idx*4] = chr(1)
+ # Just check that this is a pointer to something non-empty:
+ assert not self.valid_ndr("".join(data))
+
+ newdata = self.find_base_request("".join(data))
+
+ if newdata is None:
+ return None
+
+ assert newdata.startswith(data)
+
+ return newdata[len(data):]
+
+ def find_idl(self):
+ base_request = self.find_base_request()
+
+ if base_request is None:
+ raise Exception("Unable to determine base size for opnum %d" % self.opnum)
+
+ print "\tBase request is %r" % base_request
+
+ decision_byte_map = map(lambda x: self.check_decision_byte(base_request, x), range(len(base_request)))
+
+ print decision_byte_map
+
+ # find pointers
+ possible_pointers = map(all,
+ [decision_byte_map[i*4:(i+1)*4] for i in range(int(len(base_request)/4))])
+ print possible_pointers
+
+ pointer_deferrant_bases = map(
+ lambda x: self.find_deferrant_data(base_request, x) if possible_pointers[x] else None, range(len(possible_pointers)))
+
+ print pointer_deferrant_bases
+
+
+if len(sys.argv) < 3:
+ print "Usage: autoidl <binding> <UUID> [<version>]"
+ sys.exit(1)
+
+(binding, uuid) = sys.argv[1:3]
+if len(sys.argv) == 4:
+ version = sys.argv[3]
+else:
+ version = None
+
+if version is None:
+ for i in range(MAX_IFACE_VERSION):
+ try:
+ conn = ClientConnection(binding, (uuid, i))
+ except RuntimeError, (num, msg):
+ if num == NT_STATUS_NET_WRITE_FAULT:
+ continue
+ raise
+ else:
+ break
+else:
+ conn = ClientConnection(binding, (uuid, version))
+
+print "Figuring out number of connections...",
+num_funcs = find_num_funcs(conn)
+print "%d" % num_funcs
+
+# Figure out the syntax for each one
+for i in range(num_funcs):
+ print "Function %d" % i
+ data = Function(conn, i)
+ try:
+ data.find_idl()
+ except Exception, e:
+ print "Error: %r" % e
diff --git a/source4/scripting/bin/epdump.py b/source4/scripting/bin/epdump.py
new file mode 100644
index 0000000000..15dee33774
--- /dev/null
+++ b/source4/scripting/bin/epdump.py
@@ -0,0 +1,24 @@
+#!/usr/bin/python
+
+# Unix SMB/CIFS implementation.
+# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
+#
+# 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
+
+if len(sys.argv) < 2:
+ print "Usage: %s <binding-string>" % sys.argv[0]
+ sys.exit(1)
diff --git a/source4/scripting/bin/minschema.py b/source4/scripting/bin/minschema.py
new file mode 100755
index 0000000000..111557126d
--- /dev/null
+++ b/source4/scripting/bin/minschema.py
@@ -0,0 +1,585 @@
+#!/usr/bin/python
+#
+# work out the minimal schema for a set of objectclasses
+#
+
+import optparse
+
+import os, sys
+
+# Find right directory when running from source tree
+sys.path.insert(0, "bin/python")
+
+import samba
+from samba import getopt as options
+import sys
+
+parser = optparse.OptionParser("minschema <URL> <classfile>")
+sambaopts = options.SambaOptions(parser)
+parser.add_option_group(sambaopts)
+credopts = options.CredentialsOptions(parser)
+parser.add_option_group(credopts)
+parser.add_option_group(options.VersionOptions(parser))
+parser.add_option("--verbose", help="Be verbose", action="store_true")
+parser.add_option("--dump-classes", action="store_true")
+parser.add_option("--dump-attributes", action="store_true")
+parser.add_option("--dump-subschema", action="store_true")
+parser.add_option("--dump-subschema-auto", action="store_true")
+
+opts, args = parser.parse_args()
+opts.dump_all = True
+
+if opts.dump_classes:
+ opts.dump_all = False
+if opts.dump_attributes:
+ opts.dump_all = False
+if opts.dump_subschema:
+ opts.dump_all = False
+if opts.dump_subschema_auto:
+ opts.dump_all = False
+ opts.dump_subschema = True
+if opts.dump_all:
+ opts.dump_classes = True
+ opts.dump_attributes = True
+ opts.dump_subschema = True
+ opts.dump_subschema_auto = True
+
+if len(args) != 2:
+ parser.print_usage()
+ sys.exit(1)
+
+(url, classfile) = args
+
+creds = credopts.get_credentials()
+ldb = Ldb(url, credentials=creds)
+
+objectclasses = []
+attributes = []
+
+objectclasses_expanded = set()
+
+# the attributes we need for objectclasses
+class_attrs = ["objectClass",
+ "subClassOf",
+ "governsID",
+ "possSuperiors",
+ "possibleInferiors",
+ "mayContain",
+ "mustContain",
+ "auxiliaryClass",
+ "rDNAttID",
+ "showInAdvancedViewOnly",
+ "adminDisplayName",
+ "adminDescription",
+ "objectClassCategory",
+ "lDAPDisplayName",
+ "schemaIDGUID",
+ "systemOnly",
+ "systemPossSuperiors",
+ "systemMayContain",
+ "systemMustContain",
+ "systemAuxiliaryClass",
+ "defaultSecurityDescriptor",
+ "systemFlags",
+ "defaultHidingValue",
+ "objectCategory",
+ "defaultObjectCategory",
+
+ # this attributes are not used by w2k3
+ "schemaFlagsEx",
+ "msDs-IntId",
+ "msDs-Schema-Extensions",
+ "classDisplayName",
+ "isDefunct"]
+
+attrib_attrs = ["objectClass",
+ "attributeID",
+ "attributeSyntax",
+ "isSingleValued",
+ "rangeLower",
+ "rangeUpper",
+ "mAPIID",
+ "linkID",
+ "showInAdvancedViewOnly",
+ "adminDisplayName",
+ "oMObjectClass",
+ "adminDescription",
+ "oMSyntax",
+ "searchFlags",
+ "extendedCharsAllowed",
+ "lDAPDisplayName",
+ "schemaIDGUID",
+ "attributeSecurityGUID",
+ "systemOnly",
+ "systemFlags",
+ "isMemberOfPartialAttributeSet",
+ "objectCategory",
+
+ # this attributes are not used by w2k3
+ "schemaFlagsEx",
+ "msDs-IntId",
+ "msDs-Schema-Extensions",
+ "classDisplayName",
+ "isEphemeral",
+ "isDefunct"]
+
+#
+# notes:
+#
+# objectClassCategory
+# 1: structural
+# 2: abstract
+# 3: auxiliary
+
+#
+# print only if verbose is set
+#
+def dprintf(text):
+ if verbose is not None:
+ print text
+
+def get_object_cn(ldb, name):
+ attrs = ["cn"]
+
+ res = ldb.search("(ldapDisplayName=%s)" % name, rootDse["schemaNamingContext"], ldb.SCOPE_SUBTREE, attrs)
+ assert len(res) == 1
+
+ return res[0]["cn"]
+
+class Objectclass:
+ def __init__(self, ldb, name):
+ """create an objectclass object"""
+ self.name = name
+ self.cn = get_object_cn(ldb, name)
+
+
+class Attribute:
+ def __init__(self, ldb, name):
+ """create an attribute object"""
+ self.name = name
+ self.cn = get_object_cn(ldb, name)
+
+
+syntaxmap = dict()
+
+syntaxmap['2.5.5.1'] = '1.3.6.1.4.1.1466.115.121.1.12'
+syntaxmap['2.5.5.2'] = '1.3.6.1.4.1.1466.115.121.1.38'
+syntaxmap['2.5.5.3'] = '1.2.840.113556.1.4.1362'
+syntaxmap['2.5.5.4'] = '1.2.840.113556.1.4.905'
+syntaxmap['2.5.5.5'] = '1.3.6.1.4.1.1466.115.121.1.26'
+syntaxmap['2.5.5.6'] = '1.3.6.1.4.1.1466.115.121.1.36'
+syntaxmap['2.5.5.7'] = '1.2.840.113556.1.4.903'
+syntaxmap['2.5.5.8'] = '1.3.6.1.4.1.1466.115.121.1.7'
+syntaxmap['2.5.5.9'] = '1.3.6.1.4.1.1466.115.121.1.27'
+syntaxmap['2.5.5.10'] = '1.3.6.1.4.1.1466.115.121.1.40'
+syntaxmap['2.5.5.11'] = '1.3.6.1.4.1.1466.115.121.1.24'
+syntaxmap['2.5.5.12'] = '1.3.6.1.4.1.1466.115.121.1.15'
+syntaxmap['2.5.5.13'] = '1.3.6.1.4.1.1466.115.121.1.43'
+syntaxmap['2.5.5.14'] = '1.2.840.113556.1.4.904'
+syntaxmap['2.5.5.15'] = '1.2.840.113556.1.4.907'
+syntaxmap['2.5.5.16'] = '1.2.840.113556.1.4.906'
+syntaxmap['2.5.5.17'] = '1.3.6.1.4.1.1466.115.121.1.40'
+
+
+def map_attribute_syntax(s):
+ """map some attribute syntaxes from some apparently MS specific
+ syntaxes to the standard syntaxes"""
+ if syntaxmap.has_key(s):
+ return syntaxmap[s]
+ return s
+
+
+def fix_dn(dn):
+ """fix a string DN to use ${SCHEMADN}"""
+ return dn.replace(rootDse["schemaNamingContext"], "${SCHEMADN}")
+
+
+def write_ldif_one(o, attrs):
+ """dump an object as ldif"""
+ print "dn: CN=%s,${SCHEMADN}\n" % o["cn"]
+ for a in attrs:
+ if not o.has_key(a):
+ continue
+ # special case for oMObjectClass, which is a binary object
+ if a == "oMObjectClass":
+ print "%s:: %s\n" % (a, o[a])
+ continue
+ v = o[a]
+ if isinstance(v, str):
+ v = [v]
+ for j in v:
+ print "%s: %s\n" % (a, fix_dn(j))
+ print "\n"
+
+def write_ldif(o, attrs):
+ """dump an array of objects as ldif"""
+ for i in o:
+ write_ldif_one(i, attrs)
+
+
+def create_testdn(exampleDN):
+ """create a testDN based an an example DN
+ the idea is to ensure we obey any structural rules"""
+ a = exampleDN.split(",")
+ a[0] = "CN=TestDN"
+ return ",".join(a)
+
+
+def find_objectclass_properties(ldb, o):
+ """the properties of an objectclass"""
+ res = ldb.search(
+ expression="(ldapDisplayName=%s)" % o.name,
+ basedn=rootDse["schemaNamingContext"], scope=ldb.SCOPE_SUBTREE, attrs=class_attrs)
+ assert(len(res) == 1)
+ msg = res[0]
+ for a in msg:
+ o[a] = msg[a]
+
+def find_attribute_properties(ldb, o):
+ """find the properties of an attribute"""
+ res = ldb.search(
+ expression="(ldapDisplayName=%s)" % o.name,
+ basedn=rootDse["schemaNamingContext"], scope=ldb.SCOPE_SUBTREE,
+ attrs=attrib_attrs)
+ assert(len(res) == 1)
+ msg = res[0]
+ for a in msg:
+ # special case for oMObjectClass, which is a binary object
+ if a == "oMObjectClass":
+ o[a] = ldb.encode(msg[a])
+ continue
+ o[a] = msg[a]
+
+
+def find_objectclass_auto(ldb, o):
+ """find the auto-created properties of an objectclass. Only works for
+ classes that can be created using just a DN and the objectclass"""
+ if not o.has_key("exampleDN"):
+ return
+ testdn = create_testdn(o.exampleDN)
+
+ print "testdn is '%s'\n" % testdn
+
+ ldif = "dn: " + testdn
+ ldif += "\nobjectClass: " + o.name
+ try:
+ ldb.add(ldif)
+ except LdbError, e:
+ print "error adding %s: %s\n" % (o.name, e)
+ print "%s\n" % ldif
+ return
+
+ res = ldb.search("", testdn, ldb.SCOPE_BASE)
+ ldb.delete(testdn)
+
+ for a in res.msgs[0]:
+ attributes[a].autocreate = True
+
+
+def expand_objectclass(ldb, o):
+ """look at auxiliary information from a class to intuit the existance of
+ more classes needed for a minimal schema"""
+ attrs = ["auxiliaryClass", "systemAuxiliaryClass",
+ "possSuperiors", "systemPossSuperiors",
+ "subClassOf"]
+ res = ldb.search(
+ expression="(&(objectClass=classSchema)(ldapDisplayName=%s))" % o.name,
+ basedn=rootDse["schemaNamingContext"], scope=ldb.SCOPE_SUBTREE,
+ attrs=attrs)
+ print "Expanding class %s\n" % o.name
+ assert(len(res) == 1)
+ msg = res[0]
+ for a in attrs:
+ if not msg.has_key(aname):
+ continue
+ list = msg[aname]
+ if isinstance(list, str):
+ list = [msg[aname]]
+ for name in list:
+ if not objectclasses.has_key(name):
+ print "Found new objectclass '%s'\n" % name
+ objectclasses[name] = Objectclass(ldb, name)
+
+
+def add_objectclass_attributes(ldb, objectclass):
+ """add the must and may attributes from an objectclass to the full list
+ of attributes"""
+ attrs = ["mustContain", "systemMustContain",
+ "mayContain", "systemMayContain"]
+ for aname in attrs:
+ if not objectclass.has_key(aname):
+ continue
+ alist = objectclass[aname]
+ if isinstance(alist, str):
+ alist = [alist]
+ for a in alist:
+ if not attributes.has_key(a):
+ attributes[a] = Attribute(ldb, a)
+
+
+def walk_dn(ldb, dn):
+ """process an individual record, working out what attributes it has"""
+ # get a list of all possible attributes for this object
+ attrs = ["allowedAttributes"]
+ try:
+ res = ldb.search("objectClass=*", dn, ldb.SCOPE_BASE, attrs)
+ except LdbError, e:
+ print "Unable to fetch allowedAttributes for '%s' - %r\n" % (dn, e)
+ return
+ allattrs = res[0]["allowedAttributes"]
+ try:
+ res = ldb.search("objectClass=*", dn, ldb.SCOPE_BASE, allattrs)
+ except LdbError, e:
+ print "Unable to fetch all attributes for '%s' - %s\n" % (dn, e)
+ return
+ msg = res[0]
+ for a in msg:
+ if not attributes.has_key(a):
+ attributes[a] = Attribute(ldb, a)
+
+def walk_naming_context(ldb, namingContext):
+ """walk a naming context, looking for all records"""
+ try:
+ res = ldb.search("objectClass=*", namingContext, ldb.SCOPE_DEFAULT,
+ ["objectClass"])
+ except LdbError, e:
+ print "Unable to fetch objectClasses for '%s' - %s\n" % (namingContext, e)
+ return
+ for msg in res:
+ msg = res.msgs[r]["objectClass"]
+ for objectClass in msg:
+ if not objectclasses.has_key(objectClass):
+ objectclasses[objectClass] = Objectclass(ldb, objectClass)
+ objectclasses[objectClass].exampleDN = res.msgs[r]["dn"]
+ walk_dn(ldb, res.msgs[r].dn)
+
+def trim_objectclass_attributes(ldb, objectclass):
+ """trim the may attributes for an objectClass"""
+ # trim possibleInferiors,
+ # include only the classes we extracted
+ if objectclass.has_key("possibleInferiors"):
+ possinf = objectclass["possibleInferiors"]
+ newpossinf = []
+ if isinstance(possinf, str):
+ possinf = [possinf]
+ for x in possinf:
+ if objectclasses.has_key(x):
+ newpossinf[n] = x
+ n+=1
+ objectclass["possibleInferiors"] = newpossinf
+
+ # trim systemMayContain,
+ # remove duplicates
+ if objectclass.has_key("systemMayContain"):
+ sysmay = objectclass["systemMayContain"]
+ newsysmay = []
+ if isinstance(sysmay, str):
+ sysmay = [sysmay]
+ for x in sysmay:
+ if not x in newsysmay:
+ newsysmay.append(x)
+ objectclass["systemMayContain"] = newsysmay
+
+ # trim mayContain,
+ # remove duplicates
+ if not objectclass.has_key("mayContain"):
+ may = objectclass["mayContain"]
+ newmay = []
+ if isinstance(may, str):
+ may = [may]
+ for x in may:
+ if not x in newmay:
+ newmay.append(x)
+ objectclass["mayContain"] = newmay
+
+def build_objectclass(ldb, name):
+ """load the basic attributes of an objectClass"""
+ attrs = ["name"]
+ try:
+ res = ldb.search(
+ expression="(&(objectClass=classSchema)(ldapDisplayName=%s))" % name,
+ basedn=rootDse["schemaNamingContext"], scope=ldb.SCOPE_SUBTREE,
+ attrs=attrs)
+ except LdbError, e:
+ print "unknown class '%s'\n" % name
+ return None
+ if len(res) == 0:
+ print "unknown class '%s'\n" % name
+ return None
+ return Objectclass(ldb, name)
+
+def attribute_list(objectclass, attr1, attr2):
+ """form a coalesced attribute list"""
+ a1 = objectclass[attr1]
+ a2 = objectclass[attr2]
+ if isinstance(a1, str):
+ a1 = [a1]
+ if isinstance(a2, str):
+ a2 = [a2]
+ return a1 + a2
+
+def aggregate_list(name, list):
+ """write out a list in aggregate form"""
+ if list is None:
+ return
+ print "%s ( %s )" % (name, "$ ".join(list))
+
+def write_aggregate_objectclass(objectclass):
+ """write the aggregate record for an objectclass"""
+ print "objectClasses: ( %s NAME '%s' " % (objectclass.governsID, objectclass.name)
+ if not objectclass.has_key('subClassOf'):
+ print "SUP %s " % objectclass['subClassOf']
+ if objectclass.objectClassCategory == 1:
+ print "STRUCTURAL "
+ elif objectclass.objectClassCategory == 2:
+ print "ABSTRACT "
+ elif objectclass.objectClassCategory == 3:
+ print "AUXILIARY "
+
+ list = attribute_list(objectclass, "systemMustContain", "mustContain")
+ aggregate_list("MUST", list)
+
+ list = attribute_list(objectclass, "systemMayContain", "mayContain")
+ aggregate_list("MAY", list)
+
+ print ")\n"
+
+
+def write_aggregate_ditcontentrule(objectclass):
+ """write the aggregate record for an ditcontentrule"""
+ list = attribute_list(objectclass, "auxiliaryClass", "systemAuxiliaryClass")
+ if list is None:
+ return
+
+ print "dITContentRules: ( %s NAME '%s' " % (objectclass.governsID, objectclass.name)
+
+ aggregate_list("AUX", list)
+
+ may_list = None
+ must_list = None
+
+ for c in list:
+ list2 = attribute_list(objectclasses[c],
+ "mayContain", "systemMayContain")
+ may_list = may_list + list2
+ list2 = attribute_list(objectclasses[c],
+ "mustContain", "systemMustContain")
+ must_list = must_list + list2
+
+ aggregate_list("MUST", must_list)
+ aggregate_list("MAY", may_list)
+
+ print ")\n"
+
+def write_aggregate_attribute(attrib):
+ """write the aggregate record for an attribute"""
+ print "attributeTypes: ( %s NAME '%s' SYNTAX '%s' " % (
+ attrib.attributeID, attrib.name,
+ map_attribute_syntax(attrib.attributeSyntax))
+ if attrib['isSingleValued'] == "TRUE":
+ print "SINGLE-VALUE "
+ if attrib['systemOnly'] == "TRUE":
+ print "NO-USER-MODIFICATION "
+
+ print ")\n"
+
+
+def write_aggregate():
+ """write the aggregate record"""
+ print "dn: CN=Aggregate,${SCHEMADN}\n"
+ print """objectClass: top
+objectClass: subSchema
+objectCategory: CN=SubSchema,${SCHEMADN}
+"""
+ if not opts.dump_subschema_auto:
+ return
+
+ for objectclass in objectclasses:
+ write_aggregate_objectclass(objectclass)
+ for attr in attributes:
+ write_aggregate_attribute(attr)
+ for objectclass in objectclasses:
+ write_aggregate_ditcontentrule(objectclass)
+
+def load_list(file):
+ """load a list from a file"""
+ return open(file, 'r').splitlines()
+
+# get the rootDSE
+res = ldb.search("", "", ldb.SCOPE_BASE)
+rootDse = res[0]
+
+# load the list of classes we are interested in
+classes = load_list(classfile)
+for classname in classes:
+ objectclass = build_objectclass(ldb, classname)
+ if objectclass is not None:
+ objectclasses[classname] = objectclass
+
+
+#
+# expand the objectclass list as needed
+#
+expanded = 0
+
+# so EJS do not have while nor the break statement
+# cannot find any other way than doing more loops
+# than necessary to recursively expand all classes
+#
+for inf in range(500):
+ for n in objectclasses:
+ if not n in objectclasses_expanded:
+ expand_objectclass(ldb, objectclasses[i])
+ objectclasses_expanded.add(n)
+
+#
+# find objectclass properties
+#
+for objectclass in objectclasses:
+ find_objectclass_properties(ldb, objectclass)
+
+
+#
+# form the full list of attributes
+#
+for objectclass in objectclasses:
+ add_objectclass_attributes(ldb, objectclass)
+
+# and attribute properties
+for attr in attributes:
+ find_attribute_properties(ldb, attr)
+
+#
+# trim the 'may' attribute lists to those really needed
+#
+for objectclass in objectclasses:
+ trim_objectclass_attributes(ldb, objectclass)
+
+#
+# dump an ldif form of the attributes and objectclasses
+#
+if opts.dump_attributes:
+ write_ldif(attributes, attrib_attrs)
+if opts.dump_classes:
+ write_ldif(objectclasses, class_attrs)
+if opts.dump_subschema:
+ write_aggregate()
+
+if not opts.verbose:
+ sys.exit(0)
+
+#
+# dump list of objectclasses
+#
+print "objectClasses:\n"
+for objectclass in objectclasses:
+ print "\t%s\n" % objectclass
+
+print "attributes:\n"
+for attr in attributes:
+ print "\t%s\n" % attr
+
+print "autocreated attributes:\n"
+for attr in attributes:
+ if attr.autocreate:
+ print "\t%s\n" % i
diff --git a/source4/scripting/bin/mymachinepw b/source4/scripting/bin/mymachinepw
new file mode 100755
index 0000000000..3a843b5947
--- /dev/null
+++ b/source4/scripting/bin/mymachinepw
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+
+# Unix SMB/CIFS implementation.
+# Copyright (C) Volker Lendecke 2008
+# Copyright (C) Stefan Metzmacher 2008
+#
+# Extract our own machine pw from secrets.ldb
+#
+# 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 samba.param as param, ldb, sys, getopt
+
+optlist, args = getopt.getopt(sys.argv[1:], "s:")
+
+conf = param.LoadParm()
+loaded = False
+
+for o, v in optlist:
+ if o == "-s":
+ if not conf.load(v):
+ print(v + " not found")
+ exit(1)
+ loaded = True
+
+if not loaded:
+ conf.load_default()
+
+path=conf.get("private dir") + "/secrets.ldb"
+netbios=conf.get("netbios name")
+
+secrets = ldb.Ldb(path)
+
+search = "(&(objectclass=primaryDomain)(samaccountname=" + \
+ netbios + "$))"
+
+msg = secrets.search(expression=search, attrs=['secret'])
+
+if not msg:
+ print "Error:"
+ print "Password for host[%s] not found in path[%s]." % (netbios, path)
+ print "You may want to pass the smb.conf location via the -s option."
+ exit(1)
+
+password=msg[0]['secret'][0]
+
+print(password)
+exit(0)
diff --git a/source4/scripting/bin/rpcclient b/source4/scripting/bin/rpcclient
new file mode 100755
index 0000000000..aba4f9ddb3
--- /dev/null
+++ b/source4/scripting/bin/rpcclient
@@ -0,0 +1,305 @@
+#!/usr/bin/python
+
+import sys, os, string
+
+# Find right directory when running from source tree
+sys.path.insert(0, "bin/python")
+
+from cmd import Cmd
+from optparse import OptionParser
+from pprint import pprint
+
+import dcerpc, samr
+
+def swig2dict(obj):
+ """Convert a swig object to a dictionary."""
+
+ result = {}
+
+ for attr in filter(lambda x: type(x) == str, dir(obj)):
+
+ if attr[:2] == '__' and attr[-2:] == '__':
+ continue
+
+ if attr == 'this' or attr == 'thisown':
+ continue
+
+ result[attr] = getattr(obj, attr)
+
+ return result
+
+class rpcclient(Cmd):
+
+ prompt = 'rpcclient$ '
+
+ def __init__(self, server, cred):
+ Cmd.__init__(self)
+ self.server = server
+ self.cred = cred
+
+ 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(
+ 'ncacn_np:%s' % self.server,
+ dcerpc.DCERPC_SAMR_UUID, int(dcerpc.DCERPC_SAMR_VERSION),
+ self.cred)
+
+ 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(
+ 'ncacn_np:%s' % self.server,
+ dcerpc.DCERPC_SAMR_UUID, int(dcerpc.DCERPC_SAMR_VERSION),
+ self.cred)
+
+ connect_handle = samr.Connect(pipe)
+
+ print connect_handle.LookupDomain(args[0])
+
+ def do_SamrQueryDomInfo(self, line):
+ """Return information about a domain designated by its SID."""
+
+ usage = 'SamrQueryDomInfo DOMAIN_SID [info_level]'
+
+ parser = OptionParser(usage)
+ options, args = parser.parse_args(string.split(line))
+
+ if (len(args) == 0) or (len(args) > 2):
+ print 'usage:', usage
+ return
+
+ pipe = dcerpc.pipe_connect(
+ 'ncacn_np:%s' % self.server,
+ dcerpc.DCERPC_SAMR_UUID, int(dcerpc.DCERPC_SAMR_VERSION),
+ self.cred)
+
+ connect_handle = samr.Connect(pipe)
+ domain_handle = connect_handle.OpenDomain(args[0])
+
+ if (len(args) == 2):
+ result = domain_handle.QueryDomainInfo(int(args[1]))
+ else:
+ result = domain_handle.QueryDomainInfo()
+
+ pprint(swig2dict(result))
+
+ def do_SamrQueryDomInfo2(self, line):
+ """Return information about a domain designated by its SID.
+ (Windows 2000 and >)"""
+
+ usage = 'SamrQueryDomInfo2 DOMAIN_SID [info_level] (Windows 2000 and >)'
+ parser = OptionParser(usage)
+ options, args = parser.parse_args(string.split(line))
+
+ if len(args) == 0 or len(args) > 2:
+ print 'usage:', usage
+ return
+
+ pipe = dcerpc.pipe_connect(
+ 'ncacn_np:%s' % self.server,
+ dcerpc.DCERPC_SAMR_UUID, int(dcerpc.DCERPC_SAMR_VERSION),
+ self.cred)
+
+ connect_handle = samr.Connect(pipe)
+ domain_handle = connect_handle.OpenDomain(args[0])
+
+ if (len(args) == 2):
+ result = domain_handle.QueryDomainInfo2(int(args[1]))
+ else:
+ result = domain_handle.QueryDomainInfo2()
+
+ pprint(swig2dict(result))
+
+ def do_SamrEnumDomainGroups(self, line):
+ """Return the list of groups of a domain designated by its SID."""
+
+ usage = 'SamrEnumDomainGroups DOMAIN_SID'
+
+ parser = OptionParser(usage)
+ options, args = parser.parse_args(string.split(line))
+
+ if len(args) != 1:
+ print 'usage:', usage
+ return
+
+ pipe = dcerpc.pipe_connect(
+ 'ncacn_np:%s' % self.server,
+ dcerpc.DCERPC_SAMR_UUID, int(dcerpc.DCERPC_SAMR_VERSION),
+ self.cred)
+
+ connect_handle = samr.Connect(pipe)
+ domain_handle = connect_handle.OpenDomain(args[0])
+
+ result = domain_handle.EnumDomainGroups()
+
+ pprint(result)
+
+ def do_SamrEnumDomainAliases(self, line):
+ """Return the list of aliases (local groups) of a domain designated
+ by its SID."""
+
+ usage = 'SamrEnumDomainAliases DOMAIN_SID'
+
+ parser = OptionParser(usage)
+ options, args = parser.parse_args(string.split(line))
+
+ if len(args) != 1:
+ print 'usage:', usage
+ return
+
+ pipe = dcerpc.pipe_connect(
+ 'ncacn_np:%s' % self.server,
+ dcerpc.DCERPC_SAMR_UUID, int(dcerpc.DCERPC_SAMR_VERSION),
+ self.cred)
+
+ connect_handle = samr.Connect(pipe)
+ domain_handle = connect_handle.OpenDomain(args[0])
+
+ result = domain_handle.EnumDomainAliases()
+
+ pprint(result)
+
+ def do_SamrEnumDomainUsers(self, line):
+ """Return the list of users of a domain designated by its SID."""
+
+ usage = 'SamrEnumDomainUsers DOMAIN_SID [user_account_flags]'
+
+ parser = OptionParser(usage)
+ options, args = parser.parse_args(string.split(line))
+
+ if (len(args) == 0) or (len(args) > 2):
+ print 'usage:', usage
+ return
+
+ pipe = dcerpc.pipe_connect(
+ 'ncacn_np:%s' % self.server,
+ dcerpc.DCERPC_SAMR_UUID, int(dcerpc.DCERPC_SAMR_VERSION),
+ self.cred)
+
+ connect_handle = samr.Connect(pipe)
+ domain_handle = connect_handle.OpenDomain(args[0])
+
+ if (len(args) == 2):
+ result = domain_handle.EnumDomainUsers(int(args[1]))
+ else:
+ result = domain_handle.EnumDomainUsers()
+
+ pprint(result)
+
+if __name__ == '__main__':
+
+ # Parse command line
+
+ usage = 'rpcclient SERVER [options]'
+
+ if len(sys.argv) == 1:
+ print usage
+ sys.exit(1)
+
+ server = sys.argv[1]
+ del(sys.argv[1])
+
+ 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, username and password
+
+ cred = None
+
+ 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
+
+ if username != '':
+ cred = (domain, username, password)
+
+ # Run command loop
+
+ c = rpcclient(server, cred)
+
+ if options.command:
+ c.onecmd(options.command)
+ sys.exit(0)
+
+ while 1:
+ try:
+ c.cmdloop()
+ except KeyboardInterrupt:
+ print 'KeyboardInterrupt'
diff --git a/source4/scripting/bin/samba3dump b/source4/scripting/bin/samba3dump
new file mode 100755
index 0000000000..c11f8dbd0d
--- /dev/null
+++ b/source4/scripting/bin/samba3dump
@@ -0,0 +1,167 @@
+#!/usr/bin/python
+#
+# Dump Samba3 data
+# Copyright Jelmer Vernooij 2005-2007
+# Released under the GNU GPL v3 or later
+#
+
+import optparse
+import os, sys
+
+# Find right directory when running from source tree
+sys.path.insert(0, "bin/python")
+
+import samba
+import samba.samba3
+
+parser = optparse.OptionParser("samba3dump <libdir> [<smb.conf>]")
+parser.add_option("--format", type="choice", metavar="FORMAT",
+ choices=["full", "summary"])
+
+opts, args = parser.parse_args()
+
+if opts.format is None:
+ opts.format = "summary"
+
+def print_header(txt):
+ print "\n%s" % txt
+ print "=" * len(txt)
+
+def print_samba3_policy(pol):
+ print_header("Account Policies")
+ print "Min password length: %d" % pol.min_password_length
+ print "Password history length: %d" % pol.password_history
+ if pol.user_must_logon_to_change_password:
+ print "User must logon to change password: %d" % pol.user_must_logon_to_change_password
+ if pol.maximum_password_age:
+ print "Maximum password age: %d" % pol.maximum_password_age
+ if pol.minimum_password_age:
+ print "Minimum password age: %d" % pol.minimum_password_age
+ if pol.lockout_duration:
+ print "Lockout duration: %d" % pol.lockout_duration
+ if pol.reset_count_minutes:
+ print "Reset Count Minutes: %d" % pol.reset_count_minutes
+ if pol.bad_lockout_minutes:
+ print "Bad Lockout Minutes: %d" % pol.bad_lockout_minutes
+ if pol.disconnect_time:
+ print "Disconnect Time: %d" % pol.disconnect_time
+ if pol.refuse_machine_password_change:
+ print "Refuse Machine Password Change: %d" % pol.refuse_machine_password_change
+
+def print_samba3_sam(samdb):
+ print_header("SAM Database")
+ for user in samdb:
+ print "%s" % user
+
+def print_samba3_shares(shares):
+ print_header("Configured shares")
+ for s in shares:
+ print "--- %s ---" % s.name
+ for p in s:
+ print "\t%s = %s" % (p.key, p.value)
+ print ""
+
+def print_samba3_secrets(secrets):
+ print_header("Secrets")
+
+ if secrets.get_auth_user():
+ print "IPC Credentials:"
+ if secrets.get_auth_user():
+ print " User: %s\n" % secrets.get_auth_user()
+ if secrets.get_auth_password():
+ print " Password: %s\n" % secrets.get_auth_password()
+ if secrets.get_auth_domain():
+ print " Domain: %s\n" % secrets.get_auth_domain()
+
+ if len(list(secrets.ldap_dns())) > 0:
+ print "LDAP passwords:"
+ for dn in secrets.ldap_dns():
+ print "\t%s -> %s" % (dn, secrets.get_ldap_bind_pw(dn))
+ print ""
+
+ print "Domains:"
+ for domain in secrets.domains():
+ print "\t--- %s ---" % domain
+ print "\tSID: %s" % secrets.get_sid(domain)
+ print "\tGUID: %s" % secrets.get_domain_guid(domain)
+ print "\tPlaintext pwd: %s" % secrets.get_machine_password(domain)
+ if secrets.get_machine_last_change_time(domain):
+ print "\tLast Changed: %lu" % secrets.get_machine_last_change_time(domain)
+ if secrets.get_machine_sec_channel_type(domain):
+ print "\tSecure Channel Type: %d\n" % secrets.get_machine_sec_channel_type(domain)
+
+ print "Trusted domains:"
+ for td in secrets.trusted_domains():
+ print td
+
+def print_samba3_regdb(regdb):
+ print_header("Registry")
+ from samba.registry import str_regtype
+
+ for k in regdb.keys():
+ print "[%s]" % k
+ for (value_name, (type, value)) in regdb.values(k).items():
+ print "\"%s\"=%s:%s" % (value_name, str_regtype(type), value)
+
+def print_samba3_winsdb(winsdb):
+ print_header("WINS Database")
+
+ for name in winsdb:
+ (ttl, ips, nb_flags) = winsdb[name]
+ print "%s, nb_flags: %s, ttl: %lu, %d ips, fst: %s" % (name, nb_flags, ttl, len(ips), ips[0])
+
+def print_samba3_groupmappings(groupdb):
+ print_header("Group Mappings")
+
+ for sid in groupdb.groupsids():
+ print "\t--- Group: %s ---" % sid
+
+def print_samba3_aliases(groupdb):
+ for sid in groupdb.aliases():
+ print "\t--- Alias: %s ---" % sid
+
+def print_samba3_idmapdb(idmapdb):
+ print_header("Winbindd SID<->GID/UID mappings")
+
+ print "User High Water Mark: %d" % idmapdb.get_user_hwm()
+ print "Group High Water Mark: %d\n" % idmapdb.get_group_hwm()
+
+ for uid in idmapdb.uids():
+ print "%s -> UID %d" % (idmapdb.get_user_sid(uid), uid)
+
+ for gid in idmapdb.gids():
+ print "%s -> GID %d" % (idmapdb.get_group_sid(gid), gid)
+
+def print_samba3(samba3):
+ print_samba3_policy(samba3.get_policy_db())
+ print_samba3_winsdb(samba3.get_wins_db())
+ print_samba3_regdb(samba3.get_registry())
+ print_samba3_secrets(samba3.get_secrets_db())
+ print_samba3_idmapdb(samba3.get_idmap_db())
+ print_samba3_sam(samba3.get_sam_db())
+ groupdb = samba3.get_groupmapping_db()
+ print_samba3_groupmappings(groupdb)
+ print_samba3_aliases(groupdb)
+ print_samba3_shares(samba3.get_shares())
+
+def print_samba3_summary(samba3):
+ print "WINS db entries: %d" % len(samba3.get_wins_db())
+ print "Registry key count: %d" % len(samba3.get_registry())
+ groupdb = samba3.get_groupmapping_db()
+ print "Groupmap count: %d" % len(list(groupdb.groupsids()))
+ print "Alias count: %d" % len(list(groupdb.aliases()))
+ idmapdb = samba3.get_idmap_db()
+ print "Idmap count: %d" % (len(list(idmapdb.uids())) + len(list(idmapdb.gids())))
+
+libdir = args[0]
+if len(args) > 1:
+ smbconf = args[1]
+else:
+ smbconf = os.path.join(libdir, "smb.conf")
+
+samba3 = samba.samba3.Samba3(libdir, smbconf)
+
+if opts.format == "summary":
+ print_samba3_summary(samba3)
+elif opts.format == "full":
+ print_samba3(samba3)
diff --git a/source4/scripting/bin/smbstatus b/source4/scripting/bin/smbstatus
new file mode 100755
index 0000000000..bbd0e84826
--- /dev/null
+++ b/source4/scripting/bin/smbstatus
@@ -0,0 +1,83 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# provide information on connected users and open files
+# Copyright ǒ Jelmer Vernooij 2008
+#
+# Based on the original in EJS:
+# Copyright Andrew Tridgell 2005
+# Released under the GNU GPL version 3 or later
+#
+
+import os, sys
+
+sys.path.insert(0, "bin/python")
+
+import optparse
+import samba.getopt as options
+from samba import irpc, messaging
+
+def show_sessions(conn):
+ """show open sessions"""
+
+ sessions = conn.smbsrv_information(irpc.SMBSRV_INFO_SESSIONS).next()
+ print "User Client Connected at"
+ print "-------------------------------------------------------------------------------"
+ for session in sessions:
+ fulluser = "%s/%s" % (session.account_name, session.domain_name)
+ print "%-30s %16s %s" % (fulluser, session.client_ip, sys.httptime(session.connect_time))
+ print ""
+
+def show_tcons(open_connection):
+ """show open tree connects"""
+ conn = open_connection("smb_server")
+ tcons = conn.smbsrv_information(irpc.SMBSRV_INFO_TCONS).next()
+ print "Share Client Connected at"
+ print "-------------------------------------------------------------------------------"
+ for tcon in tcons:
+ print "%-30s %16s %s" % (tcon.share_name, tcon.client_ip, sys.httptime(tcon.connect_time))
+
+
+def show_nbt(open_connection):
+ """show nbtd information"""
+ conn = open_connection("nbt_server")
+ stats = conn.nbtd_information(irpc.NBTD_INFO_STATISTICS).next()
+ print "NBT server statistics:"
+ fields = [("total_received", "Total received"),
+ ("total_sent", "Total sent"),
+ ("query_count", "Query count"),
+ ("register_count", "Register count"),
+ ("release_count", "Release count")]
+ for (field, description) in fields:
+ print "\t%s:\t%s" % (description, getattr(stats, field))
+ print
+
+parser = optparse.OptionParser("%s [options]" % sys.argv[0])
+sambaopts = options.SambaOptions(parser)
+parser.add_option_group(sambaopts)
+parser.add_option("--messaging-path", type="string", metavar="PATH",
+ help="messaging path")
+parser.add_option("--nbt", help="show NetBIOS status", action="store_true")
+
+opts, args = parser.parse_args()
+
+lp = sambaopts.get_loadparm()
+
+print "%s" % lp.get("server string")
+
+messaging_path = (opts.messaging_path or os.path.join(lp.get("private dir"), "smbd.tmp", "messaging"))
+
+def open_connection(name):
+ return messaging.ClientConnection(name, messaging_path=messaging_path)
+
+if opts.nbt:
+ show_nbt(open_connection)
+else:
+ try:
+ conn = open_connection("smb_server")
+ except RuntimeError, (num, msg):
+ if msg == 'NT_STATUS_OBJECT_NAME_NOT_FOUND':
+ print "No active connections"
+ else:
+ show_sessions(conn)
+ show_tcons(conn)
diff --git a/source4/scripting/bin/subunitrun b/source4/scripting/bin/subunitrun
new file mode 100755
index 0000000000..6f1086ad37
--- /dev/null
+++ b/source4/scripting/bin/subunitrun
@@ -0,0 +1,48 @@
+#!/usr/bin/python
+
+# Simple subunit testrunner for python
+# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
+#
+# 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
+
+# Find right directory when running from source tree
+sys.path.insert(0, "bin/python")
+
+from subunit import SubunitTestRunner
+from unittest import TestProgram
+import optparse
+import os
+from samba import param
+import samba.getopt as options
+import samba.tests
+
+parser = optparse.OptionParser("subunitrun [options] <tests>")
+credopts = options.CredentialsOptions(parser)
+parser.add_option_group(credopts)
+sambaopts = options.SambaOptions(parser)
+parser.add_option_group(sambaopts)
+parser.add_option_group(options.VersionOptions(parser))
+
+args = parser.parse_args()[1]
+
+samba.tests.cmdline_loadparm = sambaopts.get_loadparm()
+samba.tests.cmdline_credentials = credopts.get_credentials(samba.tests.cmdline_loadparm)
+
+param.cvar.default_config = samba.tests.cmdline_loadparm
+
+runner = SubunitTestRunner()
+program = TestProgram(module=None, argv=[sys.argv[0]] + args, testRunner=runner)