diff options
Diffstat (limited to 'source4/scripting')
63 files changed, 16445 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) diff --git a/source4/scripting/ejs/config.mk b/source4/scripting/ejs/config.mk new file mode 100644 index 0000000000..34c0a9678e --- /dev/null +++ b/source4/scripting/ejs/config.mk @@ -0,0 +1,63 @@ +[MODULE::smbcalls_config] +OUTPUT_TYPE = MERGED_OBJ +SUBSYSTEM = smbcalls +INIT_FUNCTION = smb_setup_ejs_config + +smbcalls_config_OBJ_FILES = $(ejsscriptsrcdir)/smbcalls_config.o + +[MODULE::smbcalls_ldb] +OUTPUT_TYPE = MERGED_OBJ +SUBSYSTEM = smbcalls +INIT_FUNCTION = smb_setup_ejs_ldb +PRIVATE_DEPENDENCIES = LIBLDB SAMDB LIBNDR + +smbcalls_ldb_OBJ_FILES = $(ejsscriptsrcdir)/smbcalls_ldb.o + +[MODULE::smbcalls_auth] +OUTPUT_TYPE = MERGED_OBJ +SUBSYSTEM = smbcalls +INIT_FUNCTION = smb_setup_ejs_auth +PRIVATE_DEPENDENCIES = service_auth + +smbcalls_auth_OBJ_FILES = $(ejsscriptsrcdir)/smbcalls_auth.o + +smbcalls_auth_OBJ_FILES = $(ejsscriptsrcdir)/smbcalls_auth.o + +[MODULE::smbcalls_string] +SUBSYSTEM = smbcalls +OUTPUT_TYPE = MERGED_OBJ +INIT_FUNCTION = smb_setup_ejs_string + +smbcalls_string_OBJ_FILES = $(ejsscriptsrcdir)/smbcalls_string.o + +[MODULE::smbcalls_sys] +SUBSYSTEM = smbcalls +OUTPUT_TYPE = MERGED_OBJ +INIT_FUNCTION = smb_setup_ejs_system + +smbcalls_sys_OBJ_FILES = $(ejsscriptsrcdir)/smbcalls_sys.o + +[SUBSYSTEM::smbcalls] +PRIVATE_DEPENDENCIES = \ + EJS LIBSAMBA-UTIL \ + MESSAGING \ + LIBSAMBA-NET LIBCLI_SMB LIBPOPT \ + CREDENTIALS POPT_CREDENTIALS POPT_SAMBA \ + NDR_TABLE + +smbcalls_OBJ_FILES = $(addprefix $(ejsscriptsrcdir)/, \ + smbcalls.o \ + smbcalls_options.o \ + smbcalls_creds.o \ + mprutil.o) + +$(eval $(call proto_header_template,$(ejsscriptsrcdir)/proto.h,$(smbcalls_OBJ_FILES:.o=.c))) + +####################### +# Start BINARY SMBSCRIPT +[BINARY::smbscript] +PRIVATE_DEPENDENCIES = EJS LIBSAMBA-UTIL smbcalls LIBSAMBA-HOSTCONFIG +# End BINARY SMBSCRIPT +####################### + +smbscript_OBJ_FILES = $(ejsscriptsrcdir)/smbscript.o diff --git a/source4/scripting/ejs/mprutil.c b/source4/scripting/ejs/mprutil.c new file mode 100644 index 0000000000..9143947fb8 --- /dev/null +++ b/source4/scripting/ejs/mprutil.c @@ -0,0 +1,494 @@ +/* + Unix SMB/CIFS implementation. + + utility functions for manipulating mpr variables in ejs calls + + Copyright (C) Andrew Tridgell 2005 + + 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/>. +*/ + +#include "includes.h" +#include "lib/appweb/ejs/ejs.h" +#include "lib/ldb/include/ldb.h" +#include "scripting/ejs/smbcalls.h" + +/* + return a default mpr object +*/ +struct MprVar mprObject(const char *name) +{ + return ejsCreateObj(name && *name?name:"(NULL)", MPR_DEFAULT_HASH_SIZE); +} + +/* + return a empty mpr array +*/ +struct MprVar mprArray(const char *name) +{ + return ejsCreateArray(name && *name?name:"(NULL)", 0); +} + +/* + find a mpr component, allowing for sub objects, using the '.' convention +*/ + NTSTATUS mprGetVar(struct MprVar **v, const char *name) +{ + const char *p = strchr(name, '.'); + char *objname; + NTSTATUS status; + if (p == NULL) { + *v = mprGetProperty(*v, name, NULL); + if (*v == NULL) { + DEBUG(1,("mprGetVar unable to find '%s'\n", name)); + return NT_STATUS_INVALID_PARAMETER; + } + return NT_STATUS_OK; + } + objname = talloc_strndup(mprMemCtx(), name, p-name); + NT_STATUS_HAVE_NO_MEMORY(objname); + *v = mprGetProperty(*v, objname, NULL); + NT_STATUS_HAVE_NO_MEMORY(*v); + status = mprGetVar(v, p+1); + talloc_free(objname); + return status; +} + + +/* + set a mpr component, allowing for sub objects, using the '.' convention + destroys 'val' after setting +*/ + NTSTATUS mprSetVar(struct MprVar *v, const char *name, struct MprVar val) +{ + const char *p = strchr(name, '.'); + char *objname; + struct MprVar *v2; + NTSTATUS status; + if (p == NULL) { + v2 = mprSetProperty(v, name, &val); + if (v2 == NULL) { + DEBUG(1,("mprSetVar unable to set '%s'\n", name)); + return NT_STATUS_INVALID_PARAMETER_MIX; + } + mprDestroyVar(&val); + return NT_STATUS_OK; + } + objname = talloc_strndup(mprMemCtx(), name, p-name); + if (objname == NULL) { + return NT_STATUS_NO_MEMORY; + } + v2 = mprGetProperty(v, objname, NULL); + if (v2 == NULL) { + mprSetVar(v, objname, mprObject(objname)); + v2 = mprGetProperty(v, objname, NULL); + } + status = mprSetVar(v2, p+1, val); + talloc_free(objname); + return status; +} + + + +/* + add an indexed array element to a property +*/ + void mprAddArray(struct MprVar *var, int i, struct MprVar v) +{ + char idx[16]; + mprItoa(i, idx, sizeof(idx)); + mprSetVar(var, idx, v); +} + +/* + construct a MprVar from a list +*/ +struct MprVar mprList(const char *name, const char **list) +{ + struct MprVar var; + int i; + + var = mprArray(name); + for (i=0;list && list[i];i++) { + mprAddArray(&var, i, mprString(list[i])); + } + return var; +} + +/* + construct a MprVar from a string, using NULL if needed +*/ +struct MprVar mprString(const char *s) +{ + if (s == NULL) { + return mprCreatePtrVar(NULL); + } + return mprCreateStringVar(s, true); +} + +/* + construct a string MprVar from a lump of data +*/ +struct MprVar mprData(const uint8_t *p, size_t length) +{ + struct MprVar var; + char *s = talloc_strndup(mprMemCtx(), (const char *)p, length); + if (s == NULL) { + return mprCreateUndefinedVar(); + } + var = mprString(s); + talloc_free(s); + return var; +} + +/* + turn a ldb_message into a ejs object variable +*/ +static struct MprVar mprLdbMessage(struct ldb_context *ldb, struct ldb_message *msg) +{ + struct MprVar var; + int i; + /* we force some attributes to always be an array in the + returned structure. This makes the scripting easier, as you don't + need a special case for the single value case */ + const char *multivalued[] = { "objectClass", "memberOf", "privilege", + "member", NULL }; + + var = mprObject(ldb_dn_alloc_linearized(msg, msg->dn)); + + for (i=0;i<msg->num_elements;i++) { + struct ldb_message_element *el = &msg->elements[i]; + struct MprVar val; + const struct ldb_schema_attribute *a; + struct ldb_val v; + + a = ldb_schema_attribute_by_name(ldb, el->name); + if (a == NULL) { + goto failed; + } + + if (el->num_values == 1 && + !str_list_check_ci(multivalued, el->name)) { + if (a->syntax->ldif_write_fn(ldb, msg, &el->values[0], &v) != 0) { + goto failed; + } + /* FIXME: nasty hack, remove me when ejs will support + * arbitrary string and does not truncate on \0 */ + if (strlen((char *)v.data) != v.length) { + val = mprDataBlob(v); + } else { + val = mprData(v.data, v.length); + } + } else { + int j; + val = mprArray(el->name); + for (j=0;j<el->num_values;j++) { + if (a->syntax->ldif_write_fn(ldb, msg, + &el->values[j], &v) != 0) { + goto failed; + } + /* FIXME: nasty hack, remove me when ejs will support + * arbitrary string and does not truncate on \0 */ + if (strlen((char *)v.data) != v.length) { + mprAddArray(&val, j, mprDataBlob(v)); + } else { + mprAddArray(&val, j, mprData(v.data, v.length)); + } + } + } + mprSetVar(&var, el->name, val); + } + + /* add the dn if it is not already specified */ + if (mprGetProperty(&var, "dn", 0) == 0) { + mprSetVar(&var, "dn", mprString(ldb_dn_alloc_linearized(msg, msg->dn))); + } + + return var; +failed: + return mprCreateUndefinedVar(); +} + + +/* + build a MprVar result object for ldb operations with lots of funky properties +*/ +struct MprVar mprLdbResult(struct ldb_context *ldb, int err, struct ldb_result *result) +{ + struct MprVar ret; + struct MprVar ary; + + ret = mprObject("ldbret"); + + mprSetVar(&ret, "error", mprCreateIntegerVar(err)); + mprSetVar(&ret, "errstr", mprString(ldb_errstring(ldb))); + + ary = mprArray("ldb_message"); + if (result) { + int i; + + for (i = 0; i < result->count; i++) { + mprAddArray(&ary, i, mprLdbMessage(ldb, result->msgs[i])); + } + } + + mprSetVar(&ret, "msgs", ary); + + /* TODO: add referrals, exteded ops, and controls */ + + return ret; +} + + +/* + turn a MprVar string variable into a const char * + */ +const char *mprToString(struct MprVar *v) +{ + if (v->trigger) { + mprReadProperty(v, 0); + } + if (!mprVarIsString(v->type)) return NULL; + return v->string; +} + +/* + turn a MprVar integer variable into an int + */ +int mprToInt(struct MprVar *v) +{ + if (v->trigger) { + mprReadProperty(v, 0); + } + if (!mprVarIsNumber(v->type)) return 0; + return mprVarToNumber(v); +} + +/* + turn a MprVar object variable into a string list + this assumes the object variable consists only of strings +*/ +const char **mprToList(TALLOC_CTX *mem_ctx, struct MprVar *v) +{ + const char **list = NULL; + struct MprVar *el; + + if (v->type != MPR_TYPE_OBJECT || + v->properties == NULL) { + return NULL; + } + for (el=mprGetFirstProperty(v, MPR_ENUM_DATA); + el; + el=mprGetNextProperty(v, el, MPR_ENUM_DATA)) { + const char *s = mprToString(el); + if (s) { + list = str_list_add(list, s); + } + } + talloc_steal(mem_ctx, list); + return list; +} + + +/* + turn a MprVar object variable into a string list + this assumes the object variable is an array of strings +*/ +const char **mprToArray(TALLOC_CTX *mem_ctx, struct MprVar *v) +{ + const char **list = NULL; + struct MprVar *len; + int length, i; + + len = mprGetProperty(v, "length", NULL); + if (len == NULL) { + return NULL; + } + length = mprToInt(len); + + for (i=0;i<length;i++) { + char idx[16]; + struct MprVar *vs; + mprItoa(i, idx, sizeof(idx)); + vs = mprGetProperty(v, idx, NULL); + if (vs == NULL || vs->type != MPR_TYPE_STRING) { + talloc_free(list); + return NULL; + } + list = str_list_add(list, mprToString(vs)); + } + talloc_steal(mem_ctx, list); + return list; +} + +/* + turn a NTSTATUS into a MprVar object with lots of funky properties +*/ +struct MprVar mprNTSTATUS(NTSTATUS status) +{ + struct MprVar res; + + res = mprObject("ntstatus"); + + mprSetVar(&res, "errstr", mprString(nt_errstr(status))); + mprSetVar(&res, "v", mprCreateIntegerVar(NT_STATUS_V(status))); + mprSetVar(&res, "is_ok", mprCreateBoolVar(NT_STATUS_IS_OK(status))); + mprSetVar(&res, "is_err", mprCreateBoolVar(NT_STATUS_IS_ERR(status))); + + return res; +} + +/* + create a data-blob in a mpr variable +*/ +struct MprVar mprDataBlob(DATA_BLOB blob) +{ + struct MprVar res; + struct datablob *pblob = talloc(mprMemCtx(), struct datablob); + *pblob = data_blob_talloc(pblob, blob.data, blob.length); + + res = mprObject("DATA_BLOB"); + + mprSetVar(&res, "size", mprCreateIntegerVar(blob.length)); + mprSetPtrChild(&res, "blob", pblob); + + return res; +} + +/* + return a data blob from a mpr var created using mprDataBlob +*/ +struct datablob *mprToDataBlob(struct MprVar *v) +{ + return talloc_get_type(mprGetPtr(v, "blob"), struct datablob); +} + +/* + turn a WERROR into a MprVar object with lots of funky properties +*/ +struct MprVar mprWERROR(WERROR status) +{ + struct MprVar res; + + res = mprObject("werror"); + + mprSetVar(&res, "errstr", mprString(win_errstr(status))); + mprSetVar(&res, "v", mprCreateIntegerVar(W_ERROR_V(status))); + mprSetVar(&res, "is_ok", mprCreateBoolVar(W_ERROR_IS_OK(status))); + mprSetVar(&res, "is_err", mprCreateBoolVar(!W_ERROR_IS_OK(status))); + + return res; +} + + +/* + set a pointer in a existing MprVar +*/ +void mprSetPtr(struct MprVar *v, const char *propname, const void *p) +{ + mprSetVar(v, propname, mprCreatePtrVar(discard_const(p))); +} + +/* + set a pointer in a existing MprVar, freeing it when the property goes away +*/ +void mprSetPtrChild(struct MprVar *v, const char *propname, const void *p) +{ + mprSetVar(v, propname, mprCreatePtrVar(discard_const(p))); + v = mprGetProperty(v, propname, NULL); + v->allocatedData = 1; + talloc_steal(mprMemCtx(), p); +} + +/* + get a pointer from a MprVar +*/ +void *mprGetPtr(struct MprVar *v, const char *propname) +{ + struct MprVar *val; + val = mprGetProperty(v, propname, NULL); + if (val == NULL) { + return NULL; + } + if (val->type != MPR_TYPE_PTR) { + return NULL; + } + return val->ptr; +} + +/* + set the return value then free the variable +*/ + void mpr_Return(int eid, struct MprVar v) +{ + ejsSetReturnValue(eid, v); + mprDestroyVar(&v); +} + +/* + set the return value then free the variable +*/ +void mpr_ReturnString(int eid, const char *s) +{ + mpr_Return(eid, mprString(s)); +} + + +/* + set a C function in a variable +*/ + void mprSetCFunction(struct MprVar *obj, const char *name, MprCFunction fn) +{ + mprSetVar(obj, name, mprCreateCFunctionVar(fn, obj, MPR_VAR_SCRIPT_HANDLE)); +} + +/* + set a string C function in a variable +*/ + void mprSetStringCFunction(struct MprVar *obj, const char *name, MprStringCFunction fn) +{ + mprSetVar(obj, name, mprCreateStringCFunctionVar(fn, obj, MPR_VAR_SCRIPT_HANDLE)); +} + +/* + get a pointer in the current object +*/ +void *mprGetThisPtr(int eid, const char *name) +{ + struct MprVar *this = mprGetProperty(ejsGetLocalObject(eid), "this", 0); + return mprGetPtr(this, name); +} + +/* + set a pointer as a child of the local object +*/ +void mprSetThisPtr(int eid, const char *name, void *ptr) +{ + struct MprVar *this = mprGetProperty(ejsGetLocalObject(eid), "this", 0); + mprSetPtrChild(this, name, ptr); +} + +/* + used by object xxx_init() routines to allow for the caller + to supply a pre-existing object to add properties to, + or create a new object. This makes inheritance easy +*/ +struct MprVar *mprInitObject(int eid, const char *name, int argc, struct MprVar **argv) +{ + if (argc > 0 && mprVarIsObject(argv[0]->type)) { + return argv[0]; + } + mpr_Return(eid, mprObject(name)); + return ejsGetReturnValue(eid); +} diff --git a/source4/scripting/ejs/smbcalls.c b/source4/scripting/ejs/smbcalls.c new file mode 100644 index 0000000000..4314b51455 --- /dev/null +++ b/source4/scripting/ejs/smbcalls.c @@ -0,0 +1,220 @@ +/* + Unix SMB/CIFS implementation. + + provide hooks into smbd C calls from ejs scripts + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Tim Potter 2005 + + 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/>. +*/ + +#include "includes.h" +#include "param/param.h" +#include "scripting/ejs/smbcalls.h" +#include "version.h" + +/* + return the type of a variable +*/ +static int ejs_typeof(MprVarHandle eid, int argc, struct MprVar **argv) +{ + const struct { + MprType type; + const char *name; + } types[] = { + { MPR_TYPE_UNDEFINED, "undefined" }, + { MPR_TYPE_NULL, "object" }, + { MPR_TYPE_BOOL, "boolean" }, + { MPR_TYPE_CFUNCTION, "function" }, + { MPR_TYPE_FLOAT, "number" }, + { MPR_TYPE_INT, "number" }, + { MPR_TYPE_INT64, "number" }, + { MPR_TYPE_OBJECT, "object" }, + { MPR_TYPE_FUNCTION, "function" }, + { MPR_TYPE_STRING, "string" }, + { MPR_TYPE_STRING_CFUNCTION, "function" }, + { MPR_TYPE_PTR, "pointer" } + }; + int i; + const char *type = NULL; + + if (argc != 1) return -1; + + for (i=0;i<ARRAY_SIZE(types);i++) { + if (argv[0]->type == types[i].type) { + type = types[i].name; + break; + } + } + if (type == NULL) return -1; + + mpr_ReturnString(eid, type); + return 0; +} + +/* + return the native type of a variable +*/ +static int ejs_typeof_native(MprVarHandle eid, int argc, struct MprVar **argv) +{ + const struct { + MprType type; + const char *name; + } types[] = { + { MPR_TYPE_UNDEFINED, "undefined" }, + { MPR_TYPE_NULL, "null" }, + { MPR_TYPE_BOOL, "boolean" }, + { MPR_TYPE_CFUNCTION, "c_function" }, + { MPR_TYPE_FLOAT, "float" }, + { MPR_TYPE_INT, "integer" }, + { MPR_TYPE_INT64, "integer64" }, + { MPR_TYPE_OBJECT, "object" }, + { MPR_TYPE_FUNCTION, "js_function" }, + { MPR_TYPE_STRING, "string" }, + { MPR_TYPE_STRING_CFUNCTION, "string_c_function" }, + { MPR_TYPE_PTR, "pointer" } + }; + int i; + const char *type = NULL; + + if (argc != 1) return -1; + + for (i=0;i<ARRAY_SIZE(types);i++) { + if (argv[0]->type == types[i].type) { + type = types[i].name; + break; + } + } + if (type == NULL) return -1; + + mpr_ReturnString(eid, type); + return 0; +} + +/* + libinclude() allows you to include js files using a search path specified + in "js include =" in smb.conf. +*/ +static int ejs_libinclude(int eid, int argc, char **argv) +{ + int i, j; + const char **js_include = lp_js_include(mprLpCtx()); + + if (js_include == NULL || js_include[0] == NULL) { + ejsSetErrorMsg(eid, "js include path not set"); + return -1; + } + + for (i = 0; i < argc; i++) { + const char *script = argv[i]; + struct MprVar result; + char *path, *emsg; + int ret; + + /* use specfied path to search for requested file */ + for (j=0;js_include[j];j++) { + path = talloc_asprintf(mprMemCtx(), "%s/%s", js_include[j], script); + if (path == NULL) { + return -1; + } + if (file_exist(path)) { + + ret = ejsEvalFile(eid, path, &result, &emsg); + talloc_free(path); + if (ret < 0) { + ejsSetErrorMsg(eid, "%s: %s", script, emsg); + return -1; + } + break; + } + talloc_free(path); + } + + if (js_include[j] == NULL) { + ejsSetErrorMsg(eid, "unable to include '%s'", script); + return -1; + } + } + return 0; +} + +/* + return the current version +*/ +static int ejs_version(MprVarHandle eid, int argc, struct MprVar **argv) +{ + mpr_ReturnString(eid, SAMBA_VERSION_STRING); + return 0; +} + + +static void (*ejs_exception_handler) (const char *) = NULL; + +_PUBLIC_ void ejs_exception(const char *reason) +{ + ejs_exception_handler(reason); +} + +/* + setup C functions that be called from ejs +*/ +void smb_setup_ejs_functions(void (*exception_handler)(const char *)) +{ + extern NTSTATUS ejs_init_security(void); + extern NTSTATUS ejs_init_initshutdown(void); + extern NTSTATUS smb_setup_ejs_reg(void); + extern NTSTATUS smb_setup_ejs_string(void); + extern NTSTATUS ejs_init_lsarpc(void); + extern NTSTATUS ejs_init_rpcecho(void); + extern NTSTATUS ejs_init_winreg(void); + extern NTSTATUS smb_setup_ejs_random(void); + extern NTSTATUS smb_setup_ejs_config(void); + extern NTSTATUS ejs_init_misc(void); + extern NTSTATUS ejs_init_netdfs(void); + extern NTSTATUS smb_setup_ejs_datablob(void); + extern NTSTATUS smb_setup_ejs_auth(void); + extern NTSTATUS smb_setup_ejs_nss(void); + extern NTSTATUS ejs_init_samr(void); + extern NTSTATUS ejs_init_wkssvc(void); + extern NTSTATUS smb_setup_ejs_system(void); + extern NTSTATUS smb_setup_ejs_ldb(void); + extern NTSTATUS ejs_init_svcctl(void); + extern NTSTATUS smb_setup_ejs_net(void); + extern NTSTATUS ejs_init_srvsvc(void); + extern NTSTATUS ejs_init_netlogon(void); + extern NTSTATUS ejs_init_drsuapi(void); + extern NTSTATUS ejs_init_irpc(void); + extern NTSTATUS ejs_init_eventlog(void); + init_module_fn static_init[] = { STATIC_smbcalls_MODULES }; + init_module_fn *shared_init; + + ejs_exception_handler = exception_handler; + + smb_setup_ejs_options(); + smb_setup_ejs_credentials(); + + shared_init = load_samba_modules(NULL, mprLpCtx(), "smbcalls"); + + run_init_functions(static_init); + run_init_functions(shared_init); + + talloc_free(shared_init); + + ejsDefineCFunction(-1, "typeof", ejs_typeof, NULL, MPR_VAR_SCRIPT_HANDLE); + ejsDefineCFunction(-1, "nativeTypeOf", ejs_typeof_native, NULL, MPR_VAR_SCRIPT_HANDLE); + ejsDefineStringCFunction(-1, "libinclude", ejs_libinclude, NULL, MPR_VAR_SCRIPT_HANDLE); + ejsDefineCFunction(-1, "version", ejs_version, NULL, MPR_VAR_SCRIPT_HANDLE); +} + diff --git a/source4/scripting/ejs/smbcalls.h b/source4/scripting/ejs/smbcalls.h new file mode 100644 index 0000000000..3aaf324b6e --- /dev/null +++ b/source4/scripting/ejs/smbcalls.h @@ -0,0 +1,42 @@ +/* + Unix SMB/CIFS implementation. + + provide hooks into smbd C calls from ejs scripts + + Copyright (C) Andrew Tridgell 2005 + + 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/>. +*/ + +#include "lib/appweb/ejs/ejs.h" +#include "lib/ldb/include/ldb.h" + +void mpr_Return(int eid, struct MprVar); +NTSTATUS mprSetVar(struct MprVar *v, const char *name, struct MprVar val); +NTSTATUS mprGetVar(struct MprVar **v, const char *name); +void mprAddArray(struct MprVar *var, int i, struct MprVar v); +void mprSetCFunction(struct MprVar *obj, const char *name, MprCFunction fn); +void mprSetStringCFunction(struct MprVar *obj, const char *name, MprStringCFunction fn); + +struct smbcalls_context { + struct event_context *event_ctx; + struct messaging_context *msg_ctx; +}; + +struct ldb_context; +struct ldb_message; +struct cli_credentials; + +#include "param/param.h" +#include "scripting/ejs/proto.h" diff --git a/source4/scripting/ejs/smbcalls_auth.c b/source4/scripting/ejs/smbcalls_auth.c new file mode 100644 index 0000000000..b67bb7ed5b --- /dev/null +++ b/source4/scripting/ejs/smbcalls_auth.c @@ -0,0 +1,243 @@ +/* + Unix SMB/CIFS implementation. + + ejs auth functions + + Copyright (C) Simo Sorce 2005 + Copyright (C) Andrew Tridgell 2005 + + 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/>. +*/ + +#include "includes.h" +#include "lib/appweb/ejs/ejs.h" +#include "auth/auth.h" +#include "auth/credentials/credentials.h" +#include "scripting/ejs/smbcalls.h" +#include "lib/events/events.h" +#include "lib/messaging/irpc.h" +#include "libcli/security/security.h" + +static int ejs_doauth(MprVarHandle eid, + TALLOC_CTX *tmp_ctx, struct MprVar *auth, + const char *username, const char *password, + const char *domain, const char *workstation, + struct socket_address *remote_host, + const char **auth_types) +{ + struct auth_usersupplied_info *user_info = NULL; + struct auth_serversupplied_info *server_info = NULL; + struct auth_session_info *session_info = NULL; + struct auth_context *auth_context; + struct MprVar *session_info_obj; + NTSTATUS nt_status; + bool set; + + struct smbcalls_context *c; + struct event_context *ev; + struct messaging_context *msg; + + /* Hope we can find an smbcalls_context somewhere up there... */ + c = talloc_find_parent_bytype(tmp_ctx, struct smbcalls_context); + if (c) { + ev = c->event_ctx; + msg = c->msg_ctx; + } else { + /* Hope we can find the event context somewhere up there... */ + ev = mprEventCtx(); + msg = messaging_client_init(tmp_ctx, lp_messaging_path(tmp_ctx, mprLpCtx()), + lp_iconv_convenience(mprLpCtx()), ev); + } + + if (auth_types) { + nt_status = auth_context_create_methods(tmp_ctx, auth_types, ev, msg, mprLpCtx(), &auth_context); + } else { + nt_status = auth_context_create(tmp_ctx, ev, msg, mprLpCtx(), &auth_context); + } + if (!NT_STATUS_IS_OK(nt_status)) { + mprSetPropertyValue(auth, "result", mprCreateBoolVar(false)); + mprSetPropertyValue(auth, "report", mprString("Auth System Failure")); + goto done; + } + + user_info = talloc(tmp_ctx, struct auth_usersupplied_info); + if (!user_info) { + mprSetPropertyValue(auth, "result", mprCreateBoolVar(false)); + mprSetPropertyValue(auth, "report", mprString("talloc failed")); + goto done; + } + + user_info->mapped_state = true; + user_info->client.account_name = username; + user_info->mapped.account_name = username; + user_info->client.domain_name = domain; + user_info->mapped.domain_name = domain; + + user_info->workstation_name = workstation; + + user_info->remote_host = remote_host; + + user_info->password_state = AUTH_PASSWORD_PLAIN; + user_info->password.plaintext = talloc_strdup(user_info, password); + + user_info->flags = USER_INFO_CASE_INSENSITIVE_USERNAME | + USER_INFO_DONT_CHECK_UNIX_ACCOUNT; + + user_info->logon_parameters = 0; + + nt_status = auth_check_password(auth_context, tmp_ctx, user_info, &server_info); + + /* Don't give the game away (any difference between no such + * user and wrong password) */ + nt_status = auth_nt_status_squash(nt_status); + + if (!NT_STATUS_IS_OK(nt_status)) { + mprSetPropertyValue(auth, "report", + mprString(talloc_strdup(mprMemCtx(), get_friendly_nt_error_msg(nt_status)))); + mprSetPropertyValue(auth, "result", mprCreateBoolVar(false)); + goto done; + } + + nt_status = auth_generate_session_info(tmp_ctx, mprEventCtx(), mprLpCtx(), server_info, &session_info); + if (!NT_STATUS_IS_OK(nt_status)) { + mprSetPropertyValue(auth, "report", mprString("Session Info generation failed")); + mprSetPropertyValue(auth, "result", mprCreateBoolVar(false)); + goto done; + } + + if (security_token_has_nt_authenticated_users(session_info->security_token)) { + mprSetPropertyValue(auth, "user_class", mprString("USER")); + set = true; + } + + if (security_token_has_builtin_administrators(session_info->security_token)) { + mprSetPropertyValue(auth, "user_class", mprString("ADMINISTRATOR")); + set = true; + } + + if (security_token_is_system(session_info->security_token)) { + mprSetPropertyValue(auth, "user_class", mprString("SYSTEM")); + set = true; + } + + if (security_token_is_anonymous(session_info->security_token)) { + mprSetPropertyValue(auth, "report", mprString("Anonymous login not permitted")); + mprSetPropertyValue(auth, "result", mprCreateBoolVar(false)); + goto done; + } + + if (!set) { + mprSetPropertyValue(auth, "report", mprString("Session Info generation failed")); + mprSetPropertyValue(auth, "result", mprCreateBoolVar(false)); + } + + session_info_obj = mprInitObject(eid, "session_info", 0, NULL); + + mprSetPtrChild(session_info_obj, "session_info", session_info); + talloc_steal(mprMemCtx(), session_info); + + mprSetProperty(auth, "session_info", session_info_obj); + mprSetPropertyValue(auth, "result", mprCreateBoolVar(server_info->authenticated)); + mprSetPropertyValue(auth, "username", mprString(server_info->account_name)); + mprSetPropertyValue(auth, "domain", mprString(server_info->domain_name)); + +done: + return 0; +} + +/* + perform user authentication, returning an array of results + +*/ +static int ejs_userAuth(MprVarHandle eid, int argc, struct MprVar **argv) +{ + TALLOC_CTX *tmp_ctx; + const char *username; + const char *password; + const char *domain; + const char *workstation; + struct MprVar auth; + struct cli_credentials *creds; + struct socket_address *remote_host; + const char *auth_types_unix[] = { "unix", NULL }; + + if (argc != 2 || argv[0]->type != MPR_TYPE_OBJECT || argv[1]->type != MPR_TYPE_OBJECT) { + ejsSetErrorMsg(eid, "userAuth invalid arguments, this function requires an object."); + return -1; + } + + /* get credential values from credentials object */ + creds = mprGetPtr(argv[0], "creds"); + if (creds == NULL) { + ejsSetErrorMsg(eid, "userAuth requires a 'creds' first parameter"); + return -1; + } + + remote_host = (struct socket_address *)mprGetPtr(argv[1], "socket_address"); + if (remote_host == NULL) { + ejsSetErrorMsg(eid, "userAuth requires a socket address second parameter"); + return -1; + } + + tmp_ctx = talloc_new(mprMemCtx()); + + username = cli_credentials_get_username(creds); + password = cli_credentials_get_password(creds); + domain = cli_credentials_get_domain(creds); + workstation = cli_credentials_get_workstation(creds); + + if (username == NULL || password == NULL || domain == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + talloc_free(tmp_ctx); + return 0; + } + + auth = mprObject("auth"); + + if (domain && (strcmp("SYSTEM USER", domain) == 0)) { + ejs_doauth(eid, tmp_ctx, &auth, username, password, domain, workstation, remote_host, auth_types_unix); + } else { + ejs_doauth(eid, tmp_ctx, &auth, username, password, domain, workstation, remote_host, NULL); + } + + mpr_Return(eid, auth); + talloc_free(tmp_ctx); + return 0; +} + +/* + initialise credentials ejs object +*/ +static int ejs_system_session(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct MprVar *obj = mprInitObject(eid, "session_info", argc, argv); + struct auth_session_info *session_info = system_session(mprMemCtx(), mprLpCtx()); + + if (session_info == NULL) { + return -1; + } + + mprSetPtrChild(obj, "session_info", session_info); + return 0; +} + +/* + setup C functions that be called from ejs +*/ +NTSTATUS smb_setup_ejs_auth(void) +{ + ejsDefineCFunction(-1, "userAuth", ejs_userAuth, NULL, MPR_VAR_SCRIPT_HANDLE); + ejsDefineCFunction(-1, "system_session", ejs_system_session, NULL, MPR_VAR_SCRIPT_HANDLE); + return NT_STATUS_OK; +} diff --git a/source4/scripting/ejs/smbcalls_config.c b/source4/scripting/ejs/smbcalls_config.c new file mode 100644 index 0000000000..eb673b3a23 --- /dev/null +++ b/source4/scripting/ejs/smbcalls_config.c @@ -0,0 +1,228 @@ +/* + Unix SMB/CIFS implementation. + + provide hooks into smbd C calls from ejs scripts + + Copyright (C) Andrew Tridgell 2005 + + 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/>. +*/ + +#include "includes.h" +#include "scripting/ejs/smbcalls.h" +#include "lib/appweb/ejs/ejs.h" +#include "param/loadparm.h" +#include "system/network.h" +#include "lib/socket/netif.h" +#include "param/param.h" + +/* + return a list of defined services +*/ +static int ejs_lpServices(MprVarHandle eid, int argc, char **argv) +{ + int i; + const char **list = NULL; + if (argc != 0) return -1; + + for (i=0;i<lp_numservices(mprLpCtx());i++) { + list = str_list_add(list, lp_servicename(lp_servicebynum(mprLpCtx(), i))); + } + talloc_steal(mprMemCtx(), list); + mpr_Return(eid, mprList("services", list)); + return 0; +} + + +/* + allow access to loadparm variables from inside ejs scripts in web apps + + can be called in 4 ways: + + v = lp.get("type:parm"); gets a parametric variable + v = lp.get("share", "type:parm"); gets a parametric variable on a share + v = lp.get("parm"); gets a global variable + v = lp.get("share", "parm"); gets a share variable + + the returned variable is a ejs object. It is an array object for lists. +*/ +static int ejs_lpGet(MprVarHandle eid, int argc, char **argv) +{ + struct parm_struct *parm = NULL; + void *parm_ptr = NULL; + int i; + + if (argc < 1) return -1; + + if (argc == 2) { + struct loadparm_service *service; + /* its a share parameter */ + service = lp_service(mprLpCtx(), argv[0]); + if (service == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + if (strchr(argv[1], ':')) { + /* its a parametric option on a share */ + const char *type = talloc_strndup(mprMemCtx(), + argv[1], + strcspn(argv[1], ":")); + const char *option = strchr(argv[1], ':') + 1; + const char *value; + if (type == NULL || option == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + value = lp_get_parametric(mprLpCtx(), service, type, option); + if (value == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + mpr_ReturnString(eid, value); + return 0; + } + + parm = lp_parm_struct(argv[1]); + if (parm == NULL || parm->class == P_GLOBAL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + parm_ptr = lp_parm_ptr(mprLpCtx(), service, parm); + } else if (strchr(argv[0], ':')) { + /* its a global parametric option */ + const char *type = talloc_strndup(mprMemCtx(), + argv[0], strcspn(argv[0], ":")); + const char *option = strchr(argv[0], ':') + 1; + const char *value; + if (type == NULL || option == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + value = lp_get_parametric(mprLpCtx(), NULL, type, option); + if (value == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + mpr_ReturnString(eid, value); + return 0; + } else { + /* its a global parameter */ + parm = lp_parm_struct(argv[0]); + if (parm == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + parm_ptr = lp_parm_ptr(mprLpCtx(), NULL, parm); + } + + if (parm == NULL || parm_ptr == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + + /* construct and return the right type of ejs object */ + switch (parm->type) { + case P_STRING: + case P_USTRING: + mpr_ReturnString(eid, *(char **)parm_ptr); + break; + case P_BOOL: + mpr_Return(eid, mprCreateBoolVar(*(bool *)parm_ptr)); + break; + case P_INTEGER: + case P_OCTAL: + case P_BYTES: + mpr_Return(eid, mprCreateIntegerVar(*(int *)parm_ptr)); + break; + case P_ENUM: + for (i=0; parm->enum_list[i].name; i++) { + if (*(int *)parm_ptr == parm->enum_list[i].value) { + mpr_ReturnString(eid, parm->enum_list[i].name); + return 0; + } + } + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + case P_LIST: + mpr_Return(eid, mprList(parm->label, *(const char ***)parm_ptr)); + break; + } + return 0; +} + +/* + v = lp.filename(); obtain filename +*/ +static int ejs_lpFilename(MprVarHandle eid, int argc, char **argv) +{ + mpr_ReturnString(eid, lp_configfile(mprLpCtx())); + return 0; +} + +/* + set a smb.conf parameter. Only sets in memory, not permanent + + can be called in 4 ways: + + ok = lp.set("parm", "value"); +*/ +static int ejs_lpSet(MprVarHandle eid, int argc, char **argv) +{ + if (argc != 2) { + ejsSetErrorMsg(eid, "lp.set invalid arguments"); + return -1; + } + + mpr_Return(eid, mprCreateBoolVar(lp_set_cmdline(mprLpCtx(), argv[0], argv[1]))); + return 0; +} + +/* + reload smb.conf + + ok = lp.reload(); +*/ +static int ejs_lpReload(MprVarHandle eid, int argc, char **argv) +{ + bool ret; + const char *filename = lp_configfile(mprLpCtx()); + + ret = lp_load(mprLpCtx(), filename); + mpr_Return(eid, mprCreateBoolVar(ret)); + return 0; +} + +/* + initialise loadparm ejs subsystem +*/ +static int ejs_loadparm_init(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct MprVar *obj = mprInitObject(eid, "loadparm", argc, argv); + + mprSetStringCFunction(obj, "get", ejs_lpGet); + mprSetStringCFunction(obj, "set", ejs_lpSet); + mprSetStringCFunction(obj, "reload", ejs_lpReload); + mprSetStringCFunction(obj, "services", ejs_lpServices); + mprSetStringCFunction(obj, "filename", ejs_lpFilename); + return 0; +} + +/* + setup C functions that be called from ejs +*/ +NTSTATUS smb_setup_ejs_config(void) +{ + ejsDefineCFunction(-1, "loadparm_init", ejs_loadparm_init, NULL, MPR_VAR_SCRIPT_HANDLE); + return NT_STATUS_OK; +} diff --git a/source4/scripting/ejs/smbcalls_creds.c b/source4/scripting/ejs/smbcalls_creds.c new file mode 100644 index 0000000000..fd73f0751f --- /dev/null +++ b/source4/scripting/ejs/smbcalls_creds.c @@ -0,0 +1,275 @@ +/* + Unix SMB/CIFS implementation. + + provide hooks credentials calls + + Copyright (C) Andrew Tridgell 2005 + + 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/>. +*/ + +#include "includes.h" +#include "scripting/ejs/smbcalls.h" +#include "lib/appweb/ejs/ejs.h" +#include "lib/cmdline/popt_common.h" +#include "auth/credentials/credentials.h" + +/* + helper function to get the local objects credentials ptr +*/ +static struct cli_credentials *ejs_creds_get_credentials(int eid) +{ + struct cli_credentials *creds = (struct cli_credentials *)mprGetThisPtr(eid, "creds"); + if (creds == NULL) { + ejsSetErrorMsg(eid, "NULL ejs credentials"); + } + return creds; +} + +/* + get a domain +*/ +static int ejs_creds_get_domain(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + + mpr_Return(eid, mprString(cli_credentials_get_domain(creds))); + return 0; +} + + +/* + set a domain +*/ +static int ejs_creds_set_domain(MprVarHandle eid, int argc, char **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + if (argc != 1) { + ejsSetErrorMsg(eid, "bad arguments to set_domain"); + return -1; + } + + cli_credentials_set_domain(creds, argv[0], CRED_SPECIFIED); + mpr_Return(eid, mprCreateBoolVar(true)); + return 0; +} + + +/* + get a username +*/ +static int ejs_creds_get_username(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + + mpr_Return(eid, mprString(cli_credentials_get_username(creds))); + return 0; +} + + +/* + set a username +*/ +static int ejs_creds_set_username(MprVarHandle eid, int argc, char **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + if (argc != 1) { + ejsSetErrorMsg(eid, "bad arguments to set_username"); + return -1; + } + + cli_credentials_set_username(creds, argv[0], CRED_SPECIFIED); + mpr_Return(eid, mprCreateBoolVar(true)); + return 0; +} + + +/* + get user password +*/ +static int ejs_creds_get_password(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + + mpr_Return(eid, mprString(cli_credentials_get_password(creds))); + return 0; +} + + +/* + set user password +*/ +static int ejs_creds_set_password(MprVarHandle eid, int argc, char **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + if (argc != 1) { + ejsSetErrorMsg(eid, "bad arguments to set_password"); + return -1; + } + + cli_credentials_set_password(creds, argv[0], CRED_SPECIFIED); + mpr_Return(eid, mprCreateBoolVar(true)); + return 0; +} + + +/* + set realm +*/ +static int ejs_creds_set_realm(MprVarHandle eid, int argc, char **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + if (argc != 1) { + ejsSetErrorMsg(eid, "bad arguments to set_realm"); + return -1; + } + + cli_credentials_set_realm(creds, argv[0], CRED_SPECIFIED); + mpr_Return(eid, mprCreateBoolVar(true)); + return 0; +} + + +/* + get realm +*/ +static int ejs_creds_get_realm(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + + mpr_Return(eid, mprString(cli_credentials_get_realm(creds))); + return 0; +} + + +/* + set workstation +*/ +static int ejs_creds_set_workstation(MprVarHandle eid, int argc, char **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + if (argc != 1) { + ejsSetErrorMsg(eid, "bad arguments to set_workstation"); + return -1; + } + + cli_credentials_set_workstation(creds, argv[0], CRED_SPECIFIED); + mpr_Return(eid, mprCreateBoolVar(true)); + return 0; +} + + +/* + get workstation +*/ +static int ejs_creds_get_workstation(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + + mpr_Return(eid, mprString(cli_credentials_get_workstation(creds))); + return 0; +} + +/* + set machine account +*/ +static int ejs_creds_set_machine_account(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + if (argc != 0) { + ejsSetErrorMsg(eid, "bad arguments to set_machine_account"); + return -1; + } + + if (NT_STATUS_IS_OK(cli_credentials_set_machine_account(creds, mprLpCtx()))) { + mpr_Return(eid, mprCreateBoolVar(true)); + } else { + mpr_Return(eid, mprCreateBoolVar(false)); + } + return 0; +} + + +/* + initialise credentials ejs object +*/ +static int ejs_credentials_obj(struct MprVar *obj, struct cli_credentials *creds) +{ + mprSetPtrChild(obj, "creds", creds); + + /* setup our object methods */ + mprSetCFunction(obj, "get_domain", ejs_creds_get_domain); + mprSetStringCFunction(obj, "set_domain", ejs_creds_set_domain); + mprSetCFunction(obj, "get_username", ejs_creds_get_username); + mprSetStringCFunction(obj, "set_username", ejs_creds_set_username); + mprSetCFunction(obj, "get_password", ejs_creds_get_password); + mprSetStringCFunction(obj, "set_password", ejs_creds_set_password); + mprSetCFunction(obj, "get_realm", ejs_creds_get_realm); + mprSetStringCFunction(obj, "set_realm", ejs_creds_set_realm); + mprSetCFunction(obj, "get_workstation", ejs_creds_get_workstation); + mprSetStringCFunction(obj, "set_workstation", ejs_creds_set_workstation); + mprSetCFunction(obj, "set_machine_account", ejs_creds_set_machine_account); + + return 0; +} + + +struct MprVar mprCredentials(struct cli_credentials *creds) +{ + struct MprVar mpv = mprObject("credentials"); + + ejs_credentials_obj(&mpv, creds); + + return mpv; +} + + +/* + initialise credentials ejs object +*/ +static int ejs_credentials_init(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct cli_credentials *creds; + struct MprVar *obj = mprInitObject(eid, "credentials", argc, argv); + + creds = cli_credentials_init(mprMemCtx()); + if (creds == NULL) { + return -1; + } + + cli_credentials_set_conf(creds, mprLpCtx()); + + return ejs_credentials_obj(obj, creds); +} + +/* + initialise cmdline credentials ejs object +*/ +int ejs_credentials_cmdline(int eid, int argc, struct MprVar **argv) +{ + struct MprVar *obj = mprInitObject(eid, "credentials", argc, argv); + if (talloc_reference(mprMemCtx(), cmdline_credentials) == NULL) { + return -1; + } + return ejs_credentials_obj(obj, cmdline_credentials); +} + +/* + setup C functions that be called from ejs +*/ +void smb_setup_ejs_credentials(void) +{ + ejsDefineCFunction(-1, "credentials_init", ejs_credentials_init, NULL, MPR_VAR_SCRIPT_HANDLE); +} + diff --git a/source4/scripting/ejs/smbcalls_ldb.c b/source4/scripting/ejs/smbcalls_ldb.c new file mode 100644 index 0000000000..4a157945af --- /dev/null +++ b/source4/scripting/ejs/smbcalls_ldb.c @@ -0,0 +1,772 @@ +/* + Unix SMB/CIFS implementation. + + provide hooks into smbd C calls from ejs scripts + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Jelmer Vernooij 2005 + + 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/>. +*/ + +#include "includes.h" +#include "scripting/ejs/smbcalls.h" +#include "lib/appweb/ejs/ejs.h" +#include "lib/ldb/include/ldb.h" +#include "lib/ldb/include/ldb_errors.h" +#include "ldb_wrap.h" +#include "dsdb/samdb/samdb.h" +#include "librpc/ndr/libndr.h" +#include "libcli/security/security.h" + +/* + get the connected db + */ +static struct ldb_context *ejs_get_ldb_context(int eid) +{ + struct ldb_context *ldb = (struct ldb_context *)mprGetThisPtr(eid, "db"); + if (ldb == NULL) { + ejsSetErrorMsg(eid, "invalid ldb connection"); + } + return ldb; +} + +/* + perform an ldb search, returning an array of results + + syntax: + res = ldb.search("expression"); + var attrs = new Array("attr1", "attr2", "attr3"); + ldb.search("expression", attrs); + var basedn = "cn=this,dc=is,dc=a,dc=test"; + ldb.search("expression", basedn, ldb.SCOPE_SUBTREE, attrs); + ldb.search("expression", basedn, ldb.SCOPE_SUBTREE, attrs, controls); +*/ +static int ejs_ldbSearch(MprVarHandle eid, int argc, struct MprVar **argv) +{ + const char **attrs = NULL; + const char *expression; + const char *base = NULL; + struct ldb_dn *basedn = NULL; + int scope = LDB_SCOPE_DEFAULT; + TALLOC_CTX *tmp_ctx = talloc_new(mprMemCtx()); + struct ldb_context *ldb; + int ret; + struct ldb_control **parsed_controls = NULL; + struct ldb_result *res=NULL; + struct ldb_request *req; + + /* validate arguments */ + if (argc < 1 || argc > 5) { + ejsSetErrorMsg(eid, "ldb.search invalid number of arguments"); + goto failed; + } + if (argc > 3 && argv[3]->type != MPR_TYPE_OBJECT) { + ejsSetErrorMsg(eid, "ldb.search attributes must be an object"); + goto failed; + } + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + expression = mprToString(argv[0]); + if (argc > 1) { + base = mprToString(argv[1]); + /* a null basedn is valid */ + } + if (base != NULL) { + basedn = ldb_dn_new(tmp_ctx, ldb, base); + if ( ! ldb_dn_validate(basedn)) { + ejsSetErrorMsg(eid, "ldb.search malformed base dn"); + goto failed; + } + } else { + basedn = ldb_get_default_basedn(ldb); + } + if (argc > 2) { + scope = mprToInt(argv[2]); + switch (scope) { + case LDB_SCOPE_DEFAULT: + case LDB_SCOPE_BASE: + case LDB_SCOPE_ONELEVEL: + case LDB_SCOPE_SUBTREE: + break; /* ok */ + default: + ejsSetErrorMsg(eid, "ldb.search invalid scope"); + goto failed; + } + } + if (argc > 3) { + attrs = mprToList(tmp_ctx, argv[3]); + } + if (argc > 4) { + const char **controls; + controls = mprToList(tmp_ctx, argv[4]); + if (controls) { + parsed_controls = ldb_parse_control_strings(ldb, tmp_ctx, controls); + if (!parsed_controls) { + ejsSetErrorMsg(eid, "ldb.search cannot parse controls: %s", + ldb_errstring(ldb)); + goto failed; + } + } + } + + res = talloc_zero(tmp_ctx, struct ldb_result); + if (!res) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_build_search_req(&req, ldb, tmp_ctx, + basedn, + scope, + expression, + attrs, + parsed_controls, + res, + ldb_search_default_callback); + + if (ret == LDB_SUCCESS) { + + ldb_set_timeout(ldb, req, 0); /* use default timeout */ + + ret = ldb_request(ldb, req); + + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + } + + if (ret != LDB_SUCCESS) { + ejsSetErrorMsg(eid, "ldb.search failed - %s", ldb_errstring(ldb)); + mpr_Return(eid, mprLdbResult(ldb, ret, NULL)); + } else { + mpr_Return(eid, mprLdbResult(ldb, ret, res)); + } + + talloc_free(tmp_ctx); + return 0; + +failed: + talloc_free(tmp_ctx); + return -1; +} + + +/* + perform an ldb add or modify +*/ +static int ejs_ldbAddModify(MprVarHandle eid, int argc, struct MprVar **argv, + int fn(struct ldb_context *, const struct ldb_message *)) +{ + const char *ldifstring; + struct ldb_context *ldb; + struct ldb_ldif *ldif; + int ret = 0, count=0; + + if (argc != 1) { + ejsSetErrorMsg(eid, "ldb.add/modify invalid arguments"); + return -1; + } + + ldifstring = mprToString(argv[0]); + if (ldifstring == NULL) { + ejsSetErrorMsg(eid, "ldb.add/modify invalid arguments"); + return -1; + } + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + while ((ldif = ldb_ldif_read_string(ldb, &ldifstring))) { + count++; + ret = fn(ldb, ldif->msg); + talloc_free(ldif); + if (ret != 0) break; + } + + if (count == 0) { + ejsSetErrorMsg(eid, "ldb.add/modify invalid ldif"); + return -1; + } + + mpr_Return(eid, mprLdbResult(ldb, ret, NULL)); + return 0; +} + + +/* + perform an ldb delete + usage: + ok = ldb.delete(dn); +*/ +static int ejs_ldbDelete(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct ldb_dn *dn; + struct ldb_context *ldb; + int ret; + + if (argc != 1) { + ejsSetErrorMsg(eid, "ldb.delete invalid arguments"); + return -1; + } + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + dn = ldb_dn_new(ldb, ldb, mprToString(argv[0])); + if ( ! ldb_dn_validate(dn)) { + ejsSetErrorMsg(eid, "ldb.delete malformed dn"); + return -1; + } + + ret = ldb_delete(ldb, dn); + + talloc_free(dn); + + mpr_Return(eid, mprLdbResult(ldb, ret, NULL)); + return 0; +} + +/* + perform an ldb rename + usage: + ok = ldb.rename(dn1, dn2); +*/ +static int ejs_ldbRename(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct ldb_dn *dn1, *dn2; + struct ldb_context *ldb; + int ret; + + if (argc != 2) { + ejsSetErrorMsg(eid, "ldb.rename invalid arguments"); + return -1; + } + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + dn1 = ldb_dn_new(ldb, ldb, mprToString(argv[0])); + dn2 = ldb_dn_new(ldb, ldb, mprToString(argv[1])); + if ( ! ldb_dn_validate(dn1) || ! ldb_dn_validate(dn2)) { + ejsSetErrorMsg(eid, "ldb.rename invalid or malformed arguments"); + return -1; + } + + ret = ldb_rename(ldb, dn1, dn2); + + talloc_free(dn1); + talloc_free(dn2); + + mpr_Return(eid, mprLdbResult(ldb, ret, NULL)); + return 0; +} + +/* + get last error message + usage: + ok = ldb.errstring(); +*/ +static int ejs_ldbErrstring(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct ldb_context *ldb; + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + mpr_Return(eid, mprString(ldb_errstring(ldb))); + return 0; +} + +/* + base64 encode + usage: + dataout = ldb.encode(datain) + */ +static int ejs_base64encode(MprVarHandle eid, int argc, struct MprVar **argv) +{ + char *ret; + + if (argc != 1) { + ejsSetErrorMsg(eid, "ldb.base64encode invalid argument count"); + return -1; + } + + if (argv[0]->type == MPR_TYPE_STRING) { + const char *orig = mprToString(argv[0]); + ret = ldb_base64_encode(mprMemCtx(), orig, strlen(orig)); + } else { + DATA_BLOB *blob; + + blob = mprToDataBlob(argv[0]); + mprAssert(blob); + ret = ldb_base64_encode(mprMemCtx(), (char *)blob->data, blob->length); + } + + if (!ret) { + mpr_Return(eid, mprCreateUndefinedVar()); + } else { + mpr_Return(eid, mprString(ret)); + } + + talloc_free(ret); + + return 0; +} + +/* + base64 decode + usage: + dataout = ldb.decode(datain) + */ +static int ejs_base64decode(MprVarHandle eid, int argc, struct MprVar **argv) +{ + char *tmp; + int ret; + + if (argc != 1) { + ejsSetErrorMsg(eid, "ldb.base64encode invalid argument count"); + return -1; + } + + tmp = talloc_strdup(mprMemCtx(), mprToString(argv[0])); + ret = ldb_base64_decode(tmp); + if (ret == -1) { + mpr_Return(eid, mprCreateUndefinedVar()); + } else { + DATA_BLOB blob; + blob.data = (uint8_t *)tmp; + blob.length = ret; + mpr_Return(eid, mprDataBlob(blob)); + } + + talloc_free(tmp); + + return 0; +} + +/* + escape a DN + usage: + dataout = ldb.dn_escape(datain) + */ +static int ejs_dn_escape(MprVarHandle eid, int argc, struct MprVar **argv) +{ + char *ret; + struct ldb_val val; + + if (argc != 1) { + ejsSetErrorMsg(eid, "ldb.dn_escape invalid argument count"); + return -1; + } + + val = data_blob_string_const(mprToString(argv[0])); + + ret = ldb_dn_escape_value(mprMemCtx(), val); + if (ret == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + } else { + mpr_Return(eid, mprString(ret)); + talloc_free(ret); + } + + return 0; +} + +/* + perform an ldb add + + syntax: + ok = ldb.add(ldifstring); +*/ +static int ejs_ldbAdd(MprVarHandle eid, int argc, struct MprVar **argv) +{ + return ejs_ldbAddModify(eid, argc, argv, ldb_add); +} + +/* + perform an ldb modify + + syntax: + ok = ldb.modify(ldifstring); +*/ +static int ejs_ldbModify(MprVarHandle eid, int argc, struct MprVar **argv) +{ + return ejs_ldbAddModify(eid, argc, argv, ldb_modify); +} + +/* + connect to a database + usage: + ok = ldb.connect(dbfile); + ok = ldb.connect(dbfile, "modules:modlist"); + + ldb.credentials or ldb.session_info may be setup first + +*/ +static int ejs_ldbConnect(MprVarHandle eid, int argc, char **argv) +{ + struct ldb_context *ldb; + struct auth_session_info *session_info = NULL; + struct cli_credentials *creds = NULL; + struct MprVar *credentials, *session; + struct MprVar *this = mprGetProperty(ejsGetLocalObject(eid), "this", 0); + + const char *dbfile; + + if (argc < 1) { + ejsSetErrorMsg(eid, "ldb.connect invalid arguments"); + return -1; + } + + credentials = mprGetProperty(this, "credentials", NULL); + if (credentials) { + creds = talloc_get_type(mprGetPtr(credentials, "creds"), struct cli_credentials); + } + + session = mprGetProperty(this, "session_info", NULL); + if (session) { + session_info = talloc_get_type(mprGetPtr(session, "session_info"), struct auth_session_info); + } + + dbfile = argv[0]; + + ldb = ldb_wrap_connect(mprMemCtx(), mprEventCtx(), mprLpCtx(), dbfile, + session_info, creds, + 0, (const char **)(argv+1)); + if (ldb == NULL) { + ejsSetErrorMsg(eid, "ldb.connect failed to open %s", dbfile); + } + + mprSetThisPtr(eid, "db", ldb); + mpr_Return(eid, mprCreateBoolVar(ldb != NULL)); + return 0; +} + + +/* + close a db connection +*/ +static int ejs_ldbClose(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct ldb_context *ldb; + + if (argc != 0) { + ejsSetErrorMsg(eid, "ldb.close invalid arguments"); + return -1; + } + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + mprSetThisPtr(eid, "db", NULL); + mpr_Return(eid, mprCreateBoolVar(true)); + return 0; +} + + +/* + start a ldb transaction + usage: + ok = ldb.transaction_start(); +*/ +static int ejs_ldbTransactionStart(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct ldb_context *ldb; + int ret; + + if (argc != 0) { + ejsSetErrorMsg(eid, "ldb.transaction_start invalid arguments"); + return -1; + } + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + ret = ldb_transaction_start(ldb); + + mpr_Return(eid, mprCreateBoolVar(ret == 0)); + return 0; +} + +/* + cancel a ldb transaction + usage: + ok = ldb.transaction_cancel(); +*/ +static int ejs_ldbTransactionCancel(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct ldb_context *ldb; + int ret; + + if (argc != 0) { + ejsSetErrorMsg(eid, "ldb.transaction_cancel invalid arguments"); + return -1; + } + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + ret = ldb_transaction_cancel(ldb); + + mpr_Return(eid, mprCreateBoolVar(ret == 0)); + return 0; +} + +/* + commit a ldb transaction + usage: + ok = ldb.transaction_commit(); +*/ +static int ejs_ldbTransactionCommit(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct ldb_context *ldb; + int ret; + + if (argc != 0) { + ejsSetErrorMsg(eid, "ldb.transaction_commit invalid arguments"); + return -1; + } + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + ret = ldb_transaction_commit(ldb); + + mpr_Return(eid, mprCreateBoolVar(ret == 0)); + return 0; +} + +/* + commit a ldb attach a dsdb_schema from ldif files + usage: + ok = ldb.attach_dsdb_schema_from_ldif("prefixMap ldif content", "definition ldif content") +*/ +static int ejs_ldb_attach_dsdb_schema_from_ldif(MprVarHandle eid, int argc, char **argv) +{ + struct ldb_context *ldb; + WERROR status; + const char *pf; + const char *df; + + if (argc != 2) { + ejsSetErrorMsg(eid, "ldb.attach_dsdb_schema_from_ldif invalid arguments"); + return -1; + } + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + pf = argv[0]; + df = argv[1]; + + status = dsdb_attach_schema_from_ldif_file(ldb, pf, df); + + mpr_Return(eid, mprWERROR(status)); + return 0; +} + +/* + set a particular invocationId against the running LDB + usage: + ok = ldb.set_ntds_invocationId("7729aa4b-f990-41ad-b81a-8b6a14090f41"); +*/ +static int ejs_ldb_set_ntds_invocationId(MprVarHandle eid, int argc, char **argv) +{ + struct ldb_context *ldb; + NTSTATUS status; + struct GUID guid; + char *guid_str; + bool ok; + + if (argc != 1) { + ejsSetErrorMsg(eid, "ldb.set_ntds_invocationId invalid arguments"); + return -1; + } + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + guid_str = argv[0]; + + status = GUID_from_string(guid_str, &guid); + if (!NT_STATUS_IS_OK(status)) { + ejsSetErrorMsg(eid, "ldb.set_ntds_invocationId - failed to parse GUID '%s' %s\n", + guid_str, nt_errstr(status)); + return -1; + } + + ok = samdb_set_ntds_invocation_id(ldb, &guid); + if (!ok) { + ejsSetErrorMsg(eid, "ldb.set_ntds_invocationId - failed to set cached ntds invocationId\n"); + return -1; + } + + mpr_Return(eid, mprCreateBoolVar(ok)); + return 0; +} + +/* + attach a particular ntds objectGUID against the current ldb + usage: + ok = ldb.set_ntds_objectGUID("7729aa4b-f990-41ad-b81a-8b6a14090f41"); +*/ +static int ejs_ldb_set_ntds_objectGUID(MprVarHandle eid, int argc, char **argv) +{ + struct ldb_context *ldb; + NTSTATUS status; + struct GUID guid; + char *guid_str; + bool ok; + + if (argc != 1) { + ejsSetErrorMsg(eid, "ldb.set_ntds_objectGUID invalid arguments"); + return -1; + } + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + guid_str = argv[0]; + + status = GUID_from_string(guid_str, &guid); + if (!NT_STATUS_IS_OK(status)) { + ejsSetErrorMsg(eid, "ldb.set_ntds_objectGUID - failed to parse GUID '%s' %s\n", + guid_str, nt_errstr(status)); + return -1; + } + + ok = samdb_set_ntds_invocation_id(ldb, &guid); + if (!ok) { + ejsSetErrorMsg(eid, "ldb.set_ntds_objectGUID - failed to set cached ntds invocationId\n"); + return -1; + } + + mpr_Return(eid, mprCreateBoolVar(ok)); + return 0; +} + +/* + attach a particular domain SID against the current ldb + usage: + ok = ldb.set_domain_sid("S-S-1-5-21-3065342217-3567412576-2214182334"); +*/ +static int ejs_ldb_set_domain_sid(MprVarHandle eid, int argc, char **argv) +{ + struct ldb_context *ldb; + struct dom_sid *dom_sid; + char *dom_sid_str; + bool ok; + + if (argc != 1) { + ejsSetErrorMsg(eid, "ldb.set_domain_sid invalid arguments"); + return -1; + } + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + dom_sid_str = argv[0]; + + dom_sid = dom_sid_parse_talloc(NULL, dom_sid_str); + if (!dom_sid) { + ejsSetErrorMsg(eid, "ldb.set_domain_sid - failed to parse domain sid '%s'\n", + dom_sid_str); + return -1; + } + + ok = samdb_set_domain_sid(ldb, dom_sid); + talloc_free(dom_sid); + if (!ok) { + ejsSetErrorMsg(eid, "ldb.set_domain_sid - failed to set cached ntds invocationId\n"); + return -1; + } + + mpr_Return(eid, mprCreateBoolVar(ok)); + return 0; +} + +/* + initialise ldb ejs subsystem +*/ +static int ejs_ldb_init(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct MprVar *ldb = mprInitObject(eid, "ldb", argc, argv); + + mprSetStringCFunction(ldb, "connect", ejs_ldbConnect); + mprSetCFunction(ldb, "search", ejs_ldbSearch); + mprSetCFunction(ldb, "add", ejs_ldbAdd); + mprSetCFunction(ldb, "modify", ejs_ldbModify); + mprSetCFunction(ldb, "del", ejs_ldbDelete); + mprSetCFunction(ldb, "rename", ejs_ldbRename); + mprSetCFunction(ldb, "errstring", ejs_ldbErrstring); + mprSetCFunction(ldb, "encode", ejs_base64encode); + mprSetCFunction(ldb, "decode", ejs_base64decode); + mprSetCFunction(ldb, "dn_escape", ejs_dn_escape); + mprSetCFunction(ldb, "close", ejs_ldbClose); + mprSetCFunction(ldb, "transaction_start", ejs_ldbTransactionStart); + mprSetCFunction(ldb, "transaction_cancel", ejs_ldbTransactionCancel); + mprSetCFunction(ldb, "transaction_commit", ejs_ldbTransactionCommit); + mprSetStringCFunction(ldb, "attach_dsdb_schema_from_ldif", + ejs_ldb_attach_dsdb_schema_from_ldif); + mprSetStringCFunction(ldb, "set_ntds_invocationId", + ejs_ldb_set_ntds_invocationId); + mprSetStringCFunction(ldb, "set_ntds_objectGUID", + ejs_ldb_set_ntds_objectGUID); + mprSetStringCFunction(ldb, "set_domain_sid", + ejs_ldb_set_domain_sid); + mprSetVar(ldb, "SCOPE_BASE", mprCreateNumberVar(LDB_SCOPE_BASE)); + mprSetVar(ldb, "SCOPE_ONE", mprCreateNumberVar(LDB_SCOPE_ONELEVEL)); + mprSetVar(ldb, "SCOPE_SUBTREE", mprCreateNumberVar(LDB_SCOPE_SUBTREE)); + mprSetVar(ldb, "SCOPE_DEFAULT", mprCreateNumberVar(LDB_SCOPE_DEFAULT)); + + return 0; +} + + +/* + setup C functions that be called from ejs +*/ +NTSTATUS smb_setup_ejs_ldb(void) +{ + ejsDefineCFunction(-1, "ldb_init", ejs_ldb_init, NULL, MPR_VAR_SCRIPT_HANDLE); + return NT_STATUS_OK; +} diff --git a/source4/scripting/ejs/smbcalls_options.c b/source4/scripting/ejs/smbcalls_options.c new file mode 100644 index 0000000000..93872baa40 --- /dev/null +++ b/source4/scripting/ejs/smbcalls_options.c @@ -0,0 +1,193 @@ +/* + Unix SMB/CIFS implementation. + + provide a command line options parsing function for ejs + + Copyright (C) Andrew Tridgell 2005 + + 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/>. +*/ + +#include "includes.h" +#include "lib/cmdline/popt_common.h" +#include "scripting/ejs/smbcalls.h" + + +/* + usage: + options = GetOptions(argv, + "realm=s", + "enablexx", + "myint=i"); + + the special options POPT_COMMON_* options are recognised and replaced + with the Samba internal options + + resulting parsed options are placed in the options object + + additional command line arguments are placed in options.ARGV +*/ + +static int ejs_GetOptions(MprVarHandle eid, int argc, struct MprVar **argv) +{ + poptContext pc; + int opt; + struct { + const char *name; + struct poptOption *table; + const char *description; + } tables[] = { + { "POPT_AUTOHELP", poptHelpOptions, "Help options:" }, + { "POPT_COMMON_SAMBA", popt_common_samba, "Common Samba options:" }, + { "POPT_COMMON_CONNECTION", popt_common_connection, "Connection options:" }, + { "POPT_COMMON_CREDENTIALS", popt_common_credentials, "Authentication options:" }, + { "POPT_COMMON_VERSION", popt_common_version, "Common Samba options:" } + }; + + struct MprVar *options = mprInitObject(eid, "options", 0, NULL); + + TALLOC_CTX *tmp_ctx = talloc_new(mprMemCtx()); + struct poptOption *long_options = NULL; + int i, num_options = 0; + int opt_argc; + const char **opt_argv; + const char **opt_names = NULL; + const int BASE_OPTNUM = 0x100000; + + /* validate arguments */ + if (argc < 1 || argv[0]->type != MPR_TYPE_OBJECT) { + ejsSetErrorMsg(eid, "GetOptions invalid arguments"); + return -1; + } + + opt_argv = mprToArray(tmp_ctx, argv[0]); + opt_argc = str_list_length(opt_argv); + + long_options = talloc_array(tmp_ctx, struct poptOption, 1); + if (long_options == NULL) { + return -1; + } + + /* create the long_options array */ + for (i=1;i<argc;i++) { + const char *optstr = mprToString(argv[i]); + int t, opt_type = POPT_ARG_NONE; + const char *s; + if (argv[i]->type != MPR_TYPE_STRING) { + ejsSetErrorMsg(eid, "GetOptions string argument"); + return -1; + } + + long_options = talloc_realloc(tmp_ctx, long_options, + struct poptOption, num_options+2); + if (long_options == NULL) { + return -1; + } + ZERO_STRUCT(long_options[num_options]); + + /* see if its one of the special samba option tables */ + for (t=0;t<ARRAY_SIZE(tables);t++) { + if (strcmp(tables[t].name, optstr) == 0) { + break; + } + } + if (t < ARRAY_SIZE(tables)) { + opt_names = str_list_add(opt_names, optstr); + talloc_steal(tmp_ctx, opt_names); + long_options[num_options].argInfo = POPT_ARG_INCLUDE_TABLE; + long_options[num_options].arg = tables[t].table; + long_options[num_options].descrip = tables[t].description; + num_options++; + continue; + } + + s = strchr(optstr, '='); + if (s) { + char *name = talloc_strndup(tmp_ctx, optstr, (int)(s-optstr)); + opt_names = str_list_add(opt_names, name); + if (s[1] == 's') { + opt_type = POPT_ARG_STRING; + } else if (s[1] == 'i') { + opt_type = POPT_ARG_INT; + } else { + ejsSetErrorMsg(eid, "GetOptions invalid option type"); + return -1; + } + talloc_free(name); + } else { + opt_names = str_list_add(opt_names, optstr); + } + talloc_steal(tmp_ctx, opt_names); + if (strlen(opt_names[num_options]) == 1) { + long_options[num_options].shortName = opt_names[num_options][0]; + } else { + long_options[num_options].longName = opt_names[num_options]; + } + long_options[num_options].argInfo = opt_type; + long_options[num_options].val = num_options + BASE_OPTNUM; + num_options++; + } + + ZERO_STRUCT(long_options[num_options]); + + pc = poptGetContext("smbscript", opt_argc, opt_argv, long_options, 0); + + /* parse the options */ + while((opt = poptGetNextOpt(pc)) != -1) { + const char *arg; + + if (opt < BASE_OPTNUM || opt >= num_options + BASE_OPTNUM) { + char *err; + err = talloc_asprintf(tmp_ctx, "%s: %s", + poptBadOption(pc, POPT_BADOPTION_NOALIAS), + poptStrerror(opt)); + mprSetVar(options, "ERROR", mprString(err)); + talloc_free(tmp_ctx); + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + opt -= BASE_OPTNUM; + arg = poptGetOptArg(pc); + if (arg == NULL) { + mprSetVar(options, opt_names[opt], mprCreateBoolVar(1)); + } else if (long_options[opt].argInfo == POPT_ARG_INT) { + int v = strtol(arg, NULL, 0); + mprSetVar(options, opt_names[opt], mprCreateIntegerVar(v)); + } else { + mprSetVar(options, opt_names[opt], mprString(arg)); + } + } + + /* setup options.argv list */ + mprSetVar(options, "ARGV", mprList("ARGV", poptGetArgs(pc))); + + poptFreeContext(pc); + + talloc_free(tmp_ctx); + + /* setup methods */ + mprSetCFunction(options, "get_credentials", ejs_credentials_cmdline); + + return 0; +} + + + +/* + setup C functions that be called from ejs +*/ +void smb_setup_ejs_options(void) +{ + ejsDefineCFunction(-1, "GetOptions", ejs_GetOptions, NULL, MPR_VAR_SCRIPT_HANDLE); +} diff --git a/source4/scripting/ejs/smbcalls_string.c b/source4/scripting/ejs/smbcalls_string.c new file mode 100644 index 0000000000..541303ff2d --- /dev/null +++ b/source4/scripting/ejs/smbcalls_string.c @@ -0,0 +1,529 @@ +/* + Unix SMB/CIFS implementation. + + provide access to string functions + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Jelmer Vernooij 2005 (substr) + + 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/>. +*/ + +#include "includes.h" +#include "scripting/ejs/smbcalls.h" +#include "lib/appweb/ejs/ejs.h" + +/* + usage: + var len = strlen(str); +*/ +static int ejs_strlen(MprVarHandle eid, int argc, char **argv) +{ + if (argc != 1) { + ejsSetErrorMsg(eid, "strlen invalid arguments"); + return -1; + } + mpr_Return(eid, mprCreateIntegerVar(strlen_m(argv[0]))); + return 0; +} + +/* + usage: + var s = strlower("UPPER"); +*/ +static int ejs_strlower(MprVarHandle eid, int argc, char **argv) +{ + char *s; + if (argc != 1) { + ejsSetErrorMsg(eid, "strlower invalid arguments"); + return -1; + } + s = strlower_talloc(mprMemCtx(), argv[0]); + mpr_Return(eid, mprString(s)); + talloc_free(s); + return 0; +} + +/* + usage: + var s = strupper("lower"); +*/ +static int ejs_strupper(MprVarHandle eid, int argc, char **argv) +{ + char *s; + if (argc != 1) { + ejsSetErrorMsg(eid, "strupper invalid arguments"); + return -1; + } + s = strupper_talloc(mprMemCtx(), argv[0]); + mpr_Return(eid, mprString(s)); + talloc_free(s); + return 0; +} + +/* + usage: + var s = strstr(string, substring); +*/ +static int ejs_strstr(MprVarHandle eid, int argc, char **argv) +{ + char *s; + if (argc != 2) { + ejsSetErrorMsg(eid, "strstr invalid arguments"); + return -1; + } + s = strstr(argv[0], argv[1]); + mpr_Return(eid, mprString(s)); + return 0; +} + +/* + usage: + var s = strspn(string, legal_chars_string); +*/ +static int ejs_strspn(MprVarHandle eid, int argc, char **argv) +{ + int len; + if (argc != 2) { + ejsSetErrorMsg(eid, "strspn invalid arguments"); + return -1; + } + len = strspn(argv[0], argv[1]); + mpr_Return(eid, mprCreateIntegerVar(len)); + return 0; +} + +/* + usage: + list = split(".", "a.foo.bar"); + list = split(".", "a.foo.bar", count); + + count is an optional count of how many splits to make + + NOTE: does not take a regular expression, unlike perl split() +*/ +static int ejs_split(MprVarHandle eid, int argc, struct MprVar **argv) +{ + const char *separator, *s; + char *p; + struct MprVar ret; + int count = 0, maxcount=0; + TALLOC_CTX *tmp_ctx = talloc_new(mprMemCtx()); + if (argc < 2 || + argv[0]->type != MPR_TYPE_STRING || + argv[1]->type != MPR_TYPE_STRING) { + ejsSetErrorMsg(eid, "split invalid arguments"); + return -1; + } + separator = mprToString(argv[0]); + s = mprToString(argv[1]); + if (argc == 3) { + maxcount = mprToInt(argv[2]); + } + + ret = mprArray("list"); + + while ((p = strstr(s, separator))) { + char *s2 = talloc_strndup(tmp_ctx, s, (int)(p-s)); + mprAddArray(&ret, count++, mprString(s2)); + talloc_free(s2); + s = p + strlen(separator); + if (maxcount != 0 && count >= maxcount) { + break; + } + } + if (*s) { + mprAddArray(&ret, count++, mprString(s)); + } + talloc_free(tmp_ctx); + mpr_Return(eid, ret); + return 0; +} + +/* + usage: + str = substr(orig[, start_offset[, length]]); + + special cases: + if start_offset < 0 then start_offset+=strlen(orig) + if length < 0 then length+=strlen(orig)-start_offset + + (as found in many other languages) +*/ +static int ejs_substr(MprVarHandle eid, int argc, struct MprVar **argv) +{ + int start_offset = 0; + int length = 0; + const char *orig; + char *target; + + if (argc < 1 || argc > 3 || + argv[0]->type != MPR_TYPE_STRING) { + ejsSetErrorMsg(eid, "substr invalid arguments"); + return -1; + } + + if (argc == 1) { + mpr_Return(eid, *argv[0]); + return 0; + } + + orig = mprToString(argv[0]); + start_offset = mprToInt(argv[1]); + length = strlen(orig); + if (start_offset < 0) start_offset += strlen(orig); + if (start_offset < 0 || start_offset > strlen(orig)) { + ejsSetErrorMsg(eid, "substr arg 2 out of bounds ([%s], %d)", orig, start_offset); + return -1; + } + + if (argc == 3) { + length = mprToInt(argv[2]); + if (length < 0) length += strlen(orig) - start_offset; + if (length < 0 || length+start_offset > strlen(orig)) { + ejsSetErrorMsg(eid, "substr arg 3 out of bounds ([%s], %d, %d)", orig, start_offset, length); + return -1; + } + } + + target = talloc_strndup(mprMemCtx(), orig+start_offset, length); + + mpr_Return(eid, mprString(target)); + + talloc_free(target); + + return 0; +} + +/* + usage: + str = join("DC=", list); +*/ +static int ejs_join(MprVarHandle eid, int argc, struct MprVar **argv) +{ + int i; + const char *separator; + char *ret = NULL; + const char **list; + TALLOC_CTX *tmp_ctx = talloc_new(mprMemCtx()); + if (argc != 2 || + argv[0]->type != MPR_TYPE_STRING || + argv[1]->type != MPR_TYPE_OBJECT) { + ejsSetErrorMsg(eid, "join invalid arguments"); + return -1; + } + + separator = mprToString(argv[0]); + list = mprToArray(tmp_ctx, argv[1]); + + if (list == NULL || list[0] == NULL) { + talloc_free(tmp_ctx); + mpr_Return(eid, mprString(NULL)); + return 0; + } + + ret = talloc_strdup(tmp_ctx, list[0]); + if (ret == NULL) { + goto failed; + } + for (i=1;list[i];i++) { + ret = talloc_asprintf_append_buffer(ret, "%s%s", separator, list[i]); + if (ret == NULL) { + goto failed; + } + } + mpr_Return(eid, mprString(ret)); + talloc_free(tmp_ctx); + return 0; +failed: + ejsSetErrorMsg(eid, "out of memory"); + return -1; +} + + +/* + blergh, C certainly makes this hard! + usage: + str = sprintf("i=%d s=%7s", 7, "foo"); +*/ +typedef char *(*_asprintf_append_t)(char *, const char *, ...); +static int ejs_sprintf(MprVarHandle eid, int argc, struct MprVar **argv) +{ + const char *format; + const char *p; + char *ret; + int a = 1; + _asprintf_append_t _asprintf_append; + TALLOC_CTX *tmp_ctx; + if (argc < 1 || argv[0]->type != MPR_TYPE_STRING) { + ejsSetErrorMsg(eid, "sprintf invalid arguments"); + return -1; + } + format = mprToString(argv[0]); + tmp_ctx = talloc_new(mprMemCtx()); + ret = talloc_strdup(tmp_ctx, ""); + + /* avoid all the format string warnings */ + _asprintf_append = (_asprintf_append_t)talloc_asprintf_append_buffer; + + /* + hackity hack ... + */ + while ((p = strchr(format, '%'))) { + char *fmt2; + int len, len_count=0; + char *tstr; + ret = talloc_asprintf_append_buffer(ret, "%*.*s", + (int)(p-format), (int)(p-format), + format); + if (ret == NULL) goto failed; + format += (int)(p-format); + len = strcspn(p+1, "dxuiofgGpXeEFcs%") + 1; + fmt2 = talloc_strndup(tmp_ctx, p, len+1); + if (fmt2 == NULL) goto failed; + len_count = count_chars(fmt2, '*'); + /* find the type string */ + tstr = &fmt2[len]; + while (tstr > fmt2 && isalpha((unsigned char)tstr[-1])) { + tstr--; + } + if (strcmp(tstr, "%") == 0) { + ret = talloc_asprintf_append_buffer(ret, "%%"); + if (ret == NULL) { + goto failed; + } + format += len+1; + continue; + } + if (len_count > 2 || + argc < a + len_count + 1) { + ejsSetErrorMsg(eid, "sprintf: not enough arguments for format"); + goto failed; + } +#define FMT_ARG(fn, type) do { \ + switch (len_count) { \ + case 0: \ + ret = _asprintf_append(ret, fmt2, \ + (type)fn(argv[a])); \ + break; \ + case 1: \ + ret = _asprintf_append(ret, fmt2, \ + (int)mprVarToNumber(argv[a]), \ + (type)fn(argv[a+1])); \ + break; \ + case 2: \ + ret = _asprintf_append(ret, fmt2, \ + (int)mprVarToNumber(argv[a]), \ + (int)mprVarToNumber(argv[a+1]), \ + (type)fn(argv[a+2])); \ + break; \ + } \ + a += len_count + 1; \ + if (ret == NULL) { \ + goto failed; \ + } \ +} while (0) + + if (strcmp(tstr, "s")==0) FMT_ARG(mprToString, const char *); + else if (strcmp(tstr, "c")==0) FMT_ARG(*mprToString, char); + else if (strcmp(tstr, "d")==0) FMT_ARG(mprVarToNumber, int); + else if (strcmp(tstr, "ld")==0) FMT_ARG(mprVarToNumber, long); + else if (strcmp(tstr, "lld")==0) FMT_ARG(mprVarToNumber, long long); + else if (strcmp(tstr, "x")==0) FMT_ARG(mprVarToNumber, int); + else if (strcmp(tstr, "lx")==0) FMT_ARG(mprVarToNumber, long); + else if (strcmp(tstr, "llx")==0) FMT_ARG(mprVarToNumber, long long); + else if (strcmp(tstr, "X")==0) FMT_ARG(mprVarToNumber, int); + else if (strcmp(tstr, "lX")==0) FMT_ARG(mprVarToNumber, long); + else if (strcmp(tstr, "llX")==0) FMT_ARG(mprVarToNumber, long long); + else if (strcmp(tstr, "u")==0) FMT_ARG(mprVarToNumber, int); + else if (strcmp(tstr, "lu")==0) FMT_ARG(mprVarToNumber, long); + else if (strcmp(tstr, "llu")==0) FMT_ARG(mprVarToNumber, long long); + else if (strcmp(tstr, "i")==0) FMT_ARG(mprVarToNumber, int); + else if (strcmp(tstr, "li")==0) FMT_ARG(mprVarToNumber, long); + else if (strcmp(tstr, "lli")==0) FMT_ARG(mprVarToNumber, long long); + else if (strcmp(tstr, "o")==0) FMT_ARG(mprVarToNumber, int); + else if (strcmp(tstr, "lo")==0) FMT_ARG(mprVarToNumber, long); + else if (strcmp(tstr, "llo")==0) FMT_ARG(mprVarToNumber, long long); + else if (strcmp(tstr, "f")==0) FMT_ARG(mprVarToFloat, double); + else if (strcmp(tstr, "lf")==0) FMT_ARG(mprVarToFloat, double); + else if (strcmp(tstr, "g")==0) FMT_ARG(mprVarToFloat, double); + else if (strcmp(tstr, "lg")==0) FMT_ARG(mprVarToFloat, double); + else if (strcmp(tstr, "e")==0) FMT_ARG(mprVarToFloat, double); + else if (strcmp(tstr, "le")==0) FMT_ARG(mprVarToFloat, double); + else if (strcmp(tstr, "E")==0) FMT_ARG(mprVarToFloat, double); + else if (strcmp(tstr, "lE")==0) FMT_ARG(mprVarToFloat, double); + else if (strcmp(tstr, "F")==0) FMT_ARG(mprVarToFloat, double); + else if (strcmp(tstr, "lF")==0) FMT_ARG(mprVarToFloat, double); + else { + ejsSetErrorMsg(eid, "sprintf: unknown format string '%s'", fmt2); + goto failed; + } + format += len+1; + } + + ret = talloc_asprintf_append_buffer(ret, "%s", format); + mpr_Return(eid, mprString(ret)); + talloc_free(tmp_ctx); + return 0; + +failed: + talloc_free(tmp_ctx); + return -1; +} + +/* + used to build your own print function + str = vsprintf(args); +*/ +static int ejs_vsprintf(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct MprVar **args, *len, *v; + int i, ret, length; + if (argc != 1 || argv[0]->type != MPR_TYPE_OBJECT) { + ejsSetErrorMsg(eid, "vsprintf invalid arguments"); + return -1; + } + v = argv[0]; + len = mprGetProperty(v, "length", NULL); + if (len == NULL) { + ejsSetErrorMsg(eid, "vsprintf takes an array"); + return -1; + } + length = mprToInt(len); + args = talloc_array(mprMemCtx(), struct MprVar *, length); + if (args == NULL) { + return -1; + } + + for (i=0;i<length;i++) { + char idx[16]; + mprItoa(i, idx, sizeof(idx)); + args[i] = mprGetProperty(v, idx, NULL); + } + + ret = ejs_sprintf(eid, length, args); + talloc_free(args); + return ret; +} + + +/* + encode a string, replacing all non-alpha with %02x form +*/ +static int ejs_encodeURIComponent(MprVarHandle eid, int argc, char **argv) +{ + int i, j, count=0; + const char *s; + char *ret; + if (argc != 1) { + ejsSetErrorMsg(eid, "encodeURIComponent invalid arguments"); + return -1; + } + + s = argv[0]; + + for (i=0;s[i];i++) { + if (!isalnum(s[i])) count++; + } + + ret = talloc_array(mprMemCtx(), char, i + count*2 + 1); + if (ret == NULL) { + return -1; + } + for (i=j=0;s[i];i++,j++) { + if (!isalnum(s[i])) { + snprintf(ret+j, 4, "%%%02X", (unsigned)s[i]); + j += 2; + } else { + ret[j] = s[i]; + } + } + ret[j] = 0; + mpr_Return(eid, mprString(ret)); + talloc_free(ret); + return 0; +} + +/* + encode a string, replacing all non-alpha of %02x form +*/ +static int ejs_decodeURIComponent(MprVarHandle eid, int argc, char **argv) +{ + int i, j, count=0; + const char *s; + char *ret; + if (argc != 1) { + ejsSetErrorMsg(eid, "decodeURIComponent invalid arguments"); + return -1; + } + + s = argv[0]; + + ret = talloc_array(mprMemCtx(), char, strlen(s) + 1); + if (ret == NULL) { + return -1; + } + + for (i=j=0;s[i];i++,j++) { + if (s[i] == '%') { + unsigned c; + if (sscanf(s+i+1, "%02X", &c) != 1) { + ejsSetErrorMsg(eid, "decodeURIComponent bad format"); + return -1; + } + ret[j] = c; + i += 2; + } else { + ret[j] = s[i]; + } + if (!isalnum(s[i])) count++; + } + + ret[j] = 0; + mpr_Return(eid, mprString(ret)); + talloc_free(ret); + return 0; +} + +/* + initialise string ejs subsystem +*/ +static int ejs_string_init(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct MprVar *obj = mprInitObject(eid, "string", argc, argv); + + mprSetCFunction(obj, "substr", ejs_substr); + mprSetStringCFunction(obj, "strlen", ejs_strlen); + mprSetStringCFunction(obj, "strlower", ejs_strlower); + mprSetStringCFunction(obj, "strupper", ejs_strupper); + mprSetStringCFunction(obj, "strstr", ejs_strstr); + mprSetStringCFunction(obj, "strspn", ejs_strspn); + mprSetCFunction(obj, "split", ejs_split); + mprSetCFunction(obj, "join", ejs_join); + mprSetCFunction(obj, "sprintf", ejs_sprintf); + mprSetCFunction(obj, "vsprintf", ejs_vsprintf); + mprSetStringCFunction(obj, "encodeURIComponent", ejs_encodeURIComponent); + mprSetStringCFunction(obj, "decodeURIComponent", ejs_decodeURIComponent); + + return 0; +} + +/* + setup C functions that be called from ejs +*/ +NTSTATUS smb_setup_ejs_string(void) +{ + ejsDefineCFunction(-1, "string_init", ejs_string_init, NULL, MPR_VAR_SCRIPT_HANDLE); + return NT_STATUS_OK; +} diff --git a/source4/scripting/ejs/smbcalls_sys.c b/source4/scripting/ejs/smbcalls_sys.c new file mode 100644 index 0000000000..00599a55bc --- /dev/null +++ b/source4/scripting/ejs/smbcalls_sys.c @@ -0,0 +1,494 @@ +/* + Unix SMB/CIFS implementation. + + provide access to system functions + + Copyright (C) Andrew Tridgell 2005 + + 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/>. +*/ + +#include "includes.h" +#include "scripting/ejs/smbcalls.h" +#include "lib/appweb/ejs/ejs.h" +#include "lib/ldb/include/ldb.h" +#include "system/time.h" +#include "system/network.h" +#include "lib/socket/netif.h" + +/* + return the list of configured network interfaces +*/ +static int ejs_sys_interfaces(MprVarHandle eid, int argc, struct MprVar **argv) +{ + int i, count; + struct MprVar ret = mprArray("interfaces"); + struct interface *ifaces; + + load_interfaces(NULL, lp_interfaces(mprLpCtx()), &ifaces); + + count = iface_count(ifaces); + for (i=0;i<count;i++) { + mprAddArray(&ret, i, mprString(iface_n_ip(ifaces, i))); + } + + talloc_free(ifaces); + mpr_Return(eid, ret); + return 0; +} + +/* + return the hostname from gethostname() +*/ +static int ejs_sys_hostname(MprVarHandle eid, int argc, struct MprVar **argv) +{ + char name[200]; + if (gethostname(name, sizeof(name)-1) == -1) { + ejsSetErrorMsg(eid, "gethostname failed - %s", strerror(errno)); + return -1; + } + mpr_Return(eid, mprString(name)); + return 0; +} + + +/* + return current time as seconds and microseconds +*/ +static int ejs_sys_gettimeofday(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct timeval tv = timeval_current(); + struct MprVar v = mprObject("timeval"); + struct MprVar sec = mprCreateIntegerVar(tv.tv_sec); + struct MprVar usec = mprCreateIntegerVar(tv.tv_usec); + + mprCreateProperty(&v, "sec", &sec); + mprCreateProperty(&v, "usec", &usec); + mpr_Return(eid, v); + return 0; +} + +/* + return current time as a 64 bit nttime value +*/ +static int ejs_sys_nttime(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct timeval tv = timeval_current(); + struct MprVar v = mprCreateNumberVar(timeval_to_nttime(&tv)); + mpr_Return(eid, v); + return 0; +} + +/* + return time as a 64 bit nttime value from a 32 bit time_t value +*/ +static int ejs_sys_unix2nttime(MprVarHandle eid, int argc, struct MprVar **argv) +{ + NTTIME nt; + struct MprVar v; + if (argc != 1 || !mprVarIsNumber(argv[0]->type)) { + ejsSetErrorMsg(eid, "sys_unix2nttime invalid arguments"); + return -1; + } + unix_to_nt_time(&nt, mprVarToNumber(argv[0])); + v = mprCreateNumberVar(nt); + mpr_Return(eid, v); + return 0; +} + +/* + return the GMT time represented by the struct tm argument, as a time_t value +*/ +static int ejs_sys_gmmktime(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct MprVar *o; + struct tm tm; + if (argc != 1 || !mprVarIsObject(argv[0]->type)) { + ejsSetErrorMsg(eid, "sys_gmmktime invalid arguments"); + return -1; + } + + o = argv[0]; +#define TM_EL(n) tm.n = mprVarToNumber(mprGetProperty(o, #n, NULL)) + TM_EL(tm_sec); + TM_EL(tm_min); + TM_EL(tm_hour); + TM_EL(tm_mday); + TM_EL(tm_mon); + TM_EL(tm_year); + TM_EL(tm_wday); + TM_EL(tm_yday); + TM_EL(tm_isdst); +#undef TM_EL + + mpr_Return(eid, mprCreateIntegerVar(mktime(&tm))); + return 0; +} + +/* + return the given time as a gmtime structure +*/ +static int ejs_sys_gmtime(MprVarHandle eid, int argc, struct MprVar **argv) +{ + time_t t; + struct MprVar ret; + struct tm *tm; + if (argc != 1 || !mprVarIsNumber(argv[0]->type)) { + ejsSetErrorMsg(eid, "sys_gmtime invalid arguments"); + return -1; + } + t = (time_t) mprVarToNumber(argv[0]); + tm = gmtime(&t); + if (tm == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + ret = mprObject("gmtime"); +#define TM_EL(n) mprSetVar(&ret, #n, mprCreateIntegerVar(tm->n)) + TM_EL(tm_sec); + TM_EL(tm_min); + TM_EL(tm_hour); + TM_EL(tm_mday); + TM_EL(tm_mon); + TM_EL(tm_year); + TM_EL(tm_wday); + TM_EL(tm_yday); + TM_EL(tm_isdst); +#undef TM_EL + + mpr_Return(eid, ret); + return 0; +} + +/* + return the given NT time as a time_t value +*/ +static int ejs_sys_nttime2unix(MprVarHandle eid, int argc, struct MprVar **argv) +{ + time_t t; + struct MprVar v; + if (argc != 1 || !mprVarIsNumber(argv[0]->type)) { + ejsSetErrorMsg(eid, "sys_ntgmtime invalid arguments"); + return -1; + } + t = nt_time_to_unix(mprVarToNumber(argv[0])); + v = mprCreateNumberVar(t); + mpr_Return(eid, v); + return 0; +} + +/* + return the given NT time as a gmtime structure +*/ +static int ejs_sys_ntgmtime(MprVarHandle eid, int argc, struct MprVar **argv) +{ + time_t t; + struct MprVar ret; + struct tm *tm; + if (argc != 1 || !mprVarIsNumber(argv[0]->type)) { + ejsSetErrorMsg(eid, "sys_ntgmtime invalid arguments"); + return -1; + } + t = nt_time_to_unix(mprVarToNumber(argv[0])); + tm = gmtime(&t); + if (tm == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + ret = mprObject("gmtime"); +#define TM_EL(n) mprSetVar(&ret, #n, mprCreateIntegerVar(tm->n)) + TM_EL(tm_sec); + TM_EL(tm_min); + TM_EL(tm_hour); + TM_EL(tm_mday); + TM_EL(tm_mon); + TM_EL(tm_year); + TM_EL(tm_wday); + TM_EL(tm_yday); + TM_EL(tm_isdst); +#undef TM_EL + + mpr_Return(eid, ret); + return 0; +} + +/* + return a ldap time string from a nttime +*/ +static int ejs_sys_ldaptime(MprVarHandle eid, int argc, struct MprVar **argv) +{ + char *s; + time_t t; + if (argc != 1 || !mprVarIsNumber(argv[0]->type)) { + ejsSetErrorMsg(eid, "sys_ldaptime invalid arguments"); + return -1; + } + t = nt_time_to_unix(mprVarToNumber(argv[0])); + s = ldb_timestring(mprMemCtx(), t); + mpr_Return(eid, mprString(s)); + talloc_free(s); + return 0; +} + +/* + return a http time string from a nttime +*/ +static int ejs_sys_httptime(MprVarHandle eid, int argc, struct MprVar **argv) +{ + char *s; + time_t t; + if (argc != 1 || !mprVarIsNumber(argv[0]->type)) { + ejsSetErrorMsg(eid, "sys_httptime invalid arguments"); + return -1; + } + t = nt_time_to_unix(mprVarToNumber(argv[0])); + s = http_timestring(mprMemCtx(), t); + mpr_Return(eid, mprString(s)); + talloc_free(s); + return 0; +} + +/* + unlink a file + ok = sys.unlink(fname); +*/ +static int ejs_sys_unlink(MprVarHandle eid, int argc, char **argv) +{ + int ret; + if (argc != 1) { + ejsSetErrorMsg(eid, "sys_unlink invalid arguments"); + return -1; + } + ret = unlink(argv[0]); + mpr_Return(eid, mprCreateBoolVar(ret == 0)); + return 0; +} + +/* + load a file as a string + usage: + string = sys.file_load(filename); +*/ +static int ejs_sys_file_load(MprVarHandle eid, int argc, char **argv) +{ + char *s; + if (argc != 1) { + ejsSetErrorMsg(eid, "sys_file_load invalid arguments"); + return -1; + } + + s = file_load(argv[0], NULL, mprMemCtx()); + mpr_Return(eid, mprString(s)); + talloc_free(s); + return 0; +} + +/* + save a file from a string + usage: + ok = sys.file_save(filename, str); +*/ +static int ejs_sys_file_save(MprVarHandle eid, int argc, char **argv) +{ + bool ret; + if (argc != 2) { + ejsSetErrorMsg(eid, "sys_file_save invalid arguments"); + return -1; + } + ret = file_save(argv[0], argv[1], strlen(argv[1])); + mpr_Return(eid, mprCreateBoolVar(ret)); + return 0; +} + +/* + mkdir() + usage: + ok = sys.mkdir(dirname, mode); +*/ +static int ejs_sys_mkdir(MprVarHandle eid, int argc, struct MprVar **argv) +{ + bool ret; + char *name; + if (argc != 2) { + ejsSetErrorMsg(eid, "sys_mkdir invalid arguments, need mkdir(dirname, mode)"); + return -1; + } + if (!mprVarIsString(argv[0]->type)) { + ejsSetErrorMsg(eid, "sys_mkdir dirname not a string"); + return -1; + } + if (!mprVarIsNumber(argv[1]->type)) { + ejsSetErrorMsg(eid, "sys_mkdir mode not a number"); + return -1; + } + mprVarToString(&name, 0, NULL, argv[0]); + ret = mkdir(name, mprVarToNumber(argv[1])); + mpr_Return(eid, mprCreateBoolVar(ret == 0)); + return 0; +} + + +/* + return fields of a stat() call +*/ +static struct MprVar mpr_stat(struct stat *st) +{ + struct MprVar ret; + ret = mprObject("stat"); + +#define ST_EL(n) mprSetVar(&ret, #n, mprCreateNumberVar(st->n)) + ST_EL(st_dev); + ST_EL(st_ino); + ST_EL(st_mode); + ST_EL(st_nlink); + ST_EL(st_uid); + ST_EL(st_gid); + ST_EL(st_rdev); + ST_EL(st_size); + ST_EL(st_blksize); + ST_EL(st_blocks); + ST_EL(st_atime); + ST_EL(st_mtime); + ST_EL(st_ctime); + + return ret; +} + +/* + usage: + var st = sys.stat(filename); + returns an object containing struct stat elements +*/ +static int ejs_sys_stat(MprVarHandle eid, int argc, char **argv) +{ + struct stat st; + /* validate arguments */ + if (argc != 1) { + ejsSetErrorMsg(eid, "sys.stat invalid arguments"); + return -1; + } + if (stat(argv[0], &st) != 0) { + mpr_Return(eid, mprCreateUndefinedVar()); + } else { + mpr_Return(eid, mpr_stat(&st)); + } + return 0; +} + +/* + usage: + var st = sys.lstat(filename); + returns an object containing struct stat elements +*/ +static int ejs_sys_lstat(MprVarHandle eid, int argc, char **argv) +{ + struct stat st; + /* validate arguments */ + if (argc != 1) { + ejsSetErrorMsg(eid, "sys.stat invalid arguments"); + return -1; + } + if (lstat(argv[0], &st) != 0) { + mpr_Return(eid, mprCreateUndefinedVar()); + } else { + mpr_Return(eid, mpr_stat(&st)); + } + return 0; +} + +/* + bitwise AND + usage: + var z = sys.bitAND(x, 0x70); +*/ +static int ejs_sys_bitAND(MprVarHandle eid, int argc, struct MprVar **argv) +{ + int x, y, z; + + if (argc != 2 || + !mprVarIsNumber(argv[0]->type) || + !mprVarIsNumber(argv[1]->type)) { + ejsSetErrorMsg(eid, "bitand invalid arguments"); + return -1; + } + x = mprToInt(argv[0]); + y = mprToInt(argv[1]); + z = x & y; + + mpr_Return(eid, mprCreateIntegerVar(z)); + return 0; +} + +/* + bitwise OR + usage: + var z = sys.bitOR(x, 0x70); +*/ +static int ejs_sys_bitOR(MprVarHandle eid, int argc, struct MprVar **argv) +{ + int x, y, z; + + if (argc != 2 || + !mprVarIsNumber(argv[0]->type) || + !mprVarIsNumber(argv[1]->type)) { + ejsSetErrorMsg(eid, "bitand invalid arguments"); + return -1; + } + x = mprToInt(argv[0]); + y = mprToInt(argv[1]); + z = x | y; + + mpr_Return(eid, mprCreateIntegerVar(z)); + return 0; +} + +/* + initialise sys ejs subsystem +*/ +static int ejs_sys_init(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct MprVar *obj = mprInitObject(eid, "sys", argc, argv); + + mprSetCFunction(obj, "interfaces", ejs_sys_interfaces); + mprSetCFunction(obj, "hostname", ejs_sys_hostname); + mprSetCFunction(obj, "nttime", ejs_sys_nttime); + mprSetCFunction(obj, "gettimeofday", ejs_sys_gettimeofday); + mprSetCFunction(obj, "unix2nttime", ejs_sys_unix2nttime); + mprSetCFunction(obj, "gmmktime", ejs_sys_gmmktime); + mprSetCFunction(obj, "gmtime", ejs_sys_gmtime); + mprSetCFunction(obj, "nttime2unix", ejs_sys_nttime2unix); + mprSetCFunction(obj, "ntgmtime", ejs_sys_ntgmtime); + mprSetCFunction(obj, "ldaptime", ejs_sys_ldaptime); + mprSetCFunction(obj, "httptime", ejs_sys_httptime); + mprSetCFunction(obj, "mkdir", ejs_sys_mkdir); + mprSetStringCFunction(obj, "unlink", ejs_sys_unlink); + mprSetStringCFunction(obj, "file_load", ejs_sys_file_load); + mprSetStringCFunction(obj, "file_save", ejs_sys_file_save); + mprSetStringCFunction(obj, "stat", ejs_sys_stat); + mprSetStringCFunction(obj, "lstat", ejs_sys_lstat); + mprSetCFunction(obj, "bitAND", ejs_sys_bitAND); + mprSetCFunction(obj, "bitOR", ejs_sys_bitOR); + + return 0; +} + + +/* + setup C functions that be called from ejs +*/ +NTSTATUS smb_setup_ejs_system(void) +{ + ejsDefineCFunction(-1, "sys_init", ejs_sys_init, NULL, MPR_VAR_SCRIPT_HANDLE); + return NT_STATUS_OK; +} diff --git a/source4/scripting/ejs/smbscript.c b/source4/scripting/ejs/smbscript.c new file mode 100644 index 0000000000..db9fc9affa --- /dev/null +++ b/source4/scripting/ejs/smbscript.c @@ -0,0 +1,129 @@ +/* + Unix SMB/CIFS implementation. + + Standalone client for ejs scripting. + + Copyright (C) Tim Potter <tpot@samba.org> 2005 + Copyright (C) Andrew Tridgell 2005 + + 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/>. +*/ + +#include "includes.h" +#include "lib/appweb/ejs/ejs.h" +#include "lib/appweb/ejs/ejsInternal.h" +#include "scripting/ejs/smbcalls.h" +#include "auth/gensec/gensec.h" +#include "ldb/include/ldb.h" +#include "dynconfig/dynconfig.h" + +static EjsId eid; + +_NORETURN_ static void smbscript_ejs_exception(const char *reason) +{ + Ejs *ep = ejsPtr(eid); + ejsSetErrorMsg(eid, "%s", reason); + fprintf(stderr, "%s", ep->error); + exit(127); +} + +int main(int argc, const char **argv) +{ + EjsHandle handle = 0; + MprVar result; + char *emsg, *script; + size_t script_size; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + const char **argv_list = NULL; + const char *fname; + struct MprVar *return_var; + int exit_status, i; + struct loadparm_context *lp_ctx; + + fault_setup(argv[0]); + + global_loadparm = lp_ctx = loadparm_init(talloc_autofree_context()); + + if (getenv("SMB_CONF_PATH")) { + lp_load(lp_ctx, getenv("SMB_CONF_PATH")); + } else { + lp_load(lp_ctx, dyn_CONFIGFILE); + } + + gensec_init(lp_ctx); + mprSetCtx(mem_ctx); + + + if (argc < 2) { + fprintf(stderr, "You must supply a script name\n"); + exit(1); + } + + fname = argv[1]; + + if (ejsOpen(NULL, NULL, NULL) != 0) { + fprintf(stderr, "smbscript: ejsOpen(): unable to initialise " + "EJS subsystem\n"); + exit(127); + } + + smb_setup_ejs_functions(smbscript_ejs_exception); + + if ((eid = ejsOpenEngine(handle, 0)) == (EjsId)-1) { + fprintf(stderr, "smbscript: ejsOpenEngine(): unable to " + "initialise an EJS engine\n"); + exit(127); + } + + /* setup ARGV[] in the ejs environment */ + for (i=1;argv[i];i++) { + argv_list = str_list_add(argv_list, argv[i]); + } + talloc_steal(mem_ctx, argv_list); + mprSetVar(ejsGetGlobalObject(eid), "ARGV", mprList("ARGV", argv_list)); + + /* load the script and advance past interpreter line*/ + script = file_load(fname, &script_size, mem_ctx); + + if (!script) { + fprintf(stderr, "Unable to load script from '%s'\n", fname); + exit(1); + } + + /* allow scriptable js */ + if (strncmp(script, "#!", 2) == 0) { + script += strcspn(script, "\r\n"); + script += strspn(script, "\r\n"); + } + /* and this copes with the ugly exec hack */ + if (strncmp(script, "exec ", 5) == 0) { + script += strcspn(script, "\r\n"); + script += strspn(script, "\r\n"); + } + + /* run the script */ + if (ejsEvalScript(eid, script, &result, &emsg) == -1) { + fprintf(stderr, "smbscript: ejsEvalScript(): %s\n", emsg); + exit(127); + } + + return_var = ejsGetReturnValue(eid); + exit_status = mprVarToNumber(return_var); + + ejsClose(); + + talloc_free(mem_ctx); + + return exit_status; +} diff --git a/source4/scripting/libjs/base.js b/source4/scripting/libjs/base.js new file mode 100644 index 0000000000..790dfeb3e0 --- /dev/null +++ b/source4/scripting/libjs/base.js @@ -0,0 +1,50 @@ +/* + base js library functions + Copyright Andrew Tridgell 2005 + released under the GNU GPL version 3 or later +*/ + +if (global["HAVE_BASE_JS"] != undefined) { + return; +} +HAVE_BASE_JS=1 + +/* bring the string functions into the global frame */ +string_init(global); + +/* + an essential function! +*/ +function printf() +{ + print(vsprintf(arguments)); +} + +/* + substitute strings of the form ${NAME} in str, replacing + with substitutions from subobj +*/ +function substitute_var(str, subobj) +{ + var list = split("${", str); + var i; + for (i=1;i<list.length;i++) { + var list2 = split("}", list[i], 1); + if ((list2.length < 2) && (list2[0] + "}" != list[i])) { + return undefined; + } + var key = list2[0]; + var val; + if (typeof(subobj[key]) == "undefined") { + val = "${" + key + "}"; + } else if (typeof(subobj[key]) == "string") { + val = subobj[key]; + } else { + var fn = subobj[key]; + val = fn(key); + } + list2[0] = "" + val; + list[i] = join("", list2); + } + return join("", list); +} diff --git a/source4/scripting/python/STATUS b/source4/scripting/python/STATUS new file mode 100644 index 0000000000..ee67b8bc7a --- /dev/null +++ b/source4/scripting/python/STATUS @@ -0,0 +1,14 @@ +dsdb/samdb/ldb_modules/tests/samba3sam.py: Fix remaining failing tests +lib/ldb/tests/python/ldap.py: Fix remaining 3 FIXME's +command-line vampire +provisioning: combine some of the python dictionaries +finish scripting/bin/smbstatus.py + +not important before making Python the default: +- hierarchy (rename samr -> dcerpc.samr, misc -> samba.misc, etc) +- scripting/python/samba/upgrade.py +- install python modules into system +- SWAT +- __ndr_pack__/__ndr_unpack__ members for the NDR struct bindings +- generate docstrings in DCE/RPC bindings +- eliminate some variables from the python interface because they can be induced diff --git a/source4/scripting/python/ac_pkg_swig.m4 b/source4/scripting/python/ac_pkg_swig.m4 new file mode 100644 index 0000000000..8d3561a0a7 --- /dev/null +++ b/source4/scripting/python/ac_pkg_swig.m4 @@ -0,0 +1,125 @@ +##### http://autoconf-archive.cryp.to/ac_pkg_swig.html +# +# SYNOPSIS +# +# AC_PROG_SWIG([major.minor.micro]) +# +# DESCRIPTION +# +# This macro searches for a SWIG installation on your system. If +# found you should call SWIG via $(SWIG). You can use the optional +# first argument to check if the version of the available SWIG is +# greater than or equal to the value of the argument. It should have +# the format: N[.N[.N]] (N is a number between 0 and 999. Only the +# first N is mandatory.) +# +# If the version argument is given (e.g. 1.3.17), AC_PROG_SWIG checks +# that the swig package is this version number or higher. +# +# In configure.in, use as: +# +# AC_PROG_SWIG(1.3.17) +# SWIG_ENABLE_CXX +# SWIG_MULTI_MODULE_SUPPORT +# SWIG_PYTHON +# +# LAST MODIFICATION +# +# 2006-10-22 +# +# COPYLEFT +# +# Copyright (c) 2006 Sebastian Huber <sebastian-huber@web.de> +# Copyright (c) 2006 Alan W. Irwin <irwin@beluga.phys.uvic.ca> +# Copyright (c) 2006 Rafael Laboissiere <rafael@laboissiere.net> +# Copyright (c) 2006 Andrew Collier <colliera@ukzn.ac.za> +# +# 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 2 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. +# +# As a special exception, the respective Autoconf Macro's copyright +# owner gives unlimited permission to copy, distribute and modify the +# configure scripts that are the output of Autoconf when processing +# the Macro. You need not follow the terms of the GNU General Public +# License when using or distributing such scripts, even though +# portions of the text of the Macro appear in them. The GNU General +# Public License (GPL) does govern all other use of the material that +# constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the +# Autoconf Macro released by the Autoconf Macro Archive. When you +# make and distribute a modified version of the Autoconf Macro, you +# may extend this special exception to the GPL to apply to your +# modified version as well. + +AC_DEFUN([AC_PROG_SWIG],[ + AC_PATH_PROG([SWIG],[swig]) + if test -z "$SWIG" ; then + AC_MSG_WARN([cannot find 'swig' program. You should look at http://www.swig.org]) + SWIG='no' + elif test -n "$1" ; then + AC_MSG_CHECKING([for SWIG version]) + [swig_version=`$SWIG -version 2>&1 | grep 'SWIG Version' | sed 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`] + AC_MSG_RESULT([$swig_version]) + if test -n "$swig_version" ; then + # Calculate the required version number components + [required=$1] + [required_major=`echo $required | sed 's/[^0-9].*//'`] + if test -z "$required_major" ; then + [required_major=0] + fi + [required=`echo $required | sed 's/[0-9]*[^0-9]//'`] + [required_minor=`echo $required | sed 's/[^0-9].*//'`] + if test -z "$required_minor" ; then + [required_minor=0] + fi + [required=`echo $required | sed 's/[0-9]*[^0-9]//'`] + [required_patch=`echo $required | sed 's/[^0-9].*//'`] + if test -z "$required_patch" ; then + [required_patch=0] + fi + # Calculate the available version number components + [available=$swig_version] + [available_major=`echo $available | sed 's/[^0-9].*//'`] + if test -z "$available_major" ; then + [available_major=0] + fi + [available=`echo $available | sed 's/[0-9]*[^0-9]//'`] + [available_minor=`echo $available | sed 's/[^0-9].*//'`] + if test -z "$available_minor" ; then + [available_minor=0] + fi + [available=`echo $available | sed 's/[0-9]*[^0-9]//'`] + [available_patch=`echo $available | sed 's/[^0-9].*//'`] + if test -z "$available_patch" ; then + [available_patch=0] + fi + if test $available_major -ne $required_major \ + -o $available_minor -ne $required_minor \ + -o $available_patch -lt $required_patch ; then + AC_MSG_WARN([SWIG version >= $1 is required if you would like to work on the SWIG bindings. You have $swig_version. ]) + SWIG='no' + else + AC_MSG_NOTICE([SWIG executable is '$SWIG']) + SWIG_LIB=`$SWIG -swiglib` + AC_MSG_NOTICE([SWIG library directory is '$SWIG_LIB']) + fi + else + AC_MSG_WARN([cannot determine SWIG version]) + SWIG='no' + fi + fi + AC_SUBST([SWIG_LIB]) +]) diff --git a/source4/scripting/python/config.m4 b/source4/scripting/python/config.m4 new file mode 100644 index 0000000000..af13b6ae69 --- /dev/null +++ b/source4/scripting/python/config.m4 @@ -0,0 +1,83 @@ +m4_include(scripting/python/ac_pkg_swig.m4) + +AC_ARG_VAR([PYTHON_VERSION],[The installed Python + version to use, for example '2.3'. This string + will be appended to the Python interpreter + canonical name.]) + +AC_PROG_SWIG(1.3.35) + +AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]]) +if test -z "$PYTHON"; then + working_python=no + AC_MSG_WARN([No python found]) +fi + +AC_DEFUN([TRY_LINK_PYTHON], +[ + if test $working_python = no; then + ac_save_LIBS="$LIBS" + ac_save_CFLAGS="$CFLAGS" + LIBS="$LIBS $1" + CFLAGS="$CFLAGS $2" + + AC_TRY_LINK([ + /* we have our own configure tests */ + #include <Python.h> + ],[ + Py_InitModule(NULL, NULL); + ],[ + PYTHON_LDFLAGS="$1" + PYTHON_CFLAGS="$2" + working_python=yes + ]) + LIBS="$ac_save_LIBS" + CFLAGS="$ac_save_CFLAGS" + fi +]) + +dnl assume no working python +working_python=no + +if test -z "$PYTHON_VERSION"; then + AC_PATH_PROGS([PYTHON_CONFIG], [python2.6-config python2.5-config python2.4-config python-config]) +else + AC_PATH_PROG([PYTHON_CONFIG], [python[$PYTHON_VERSION]-config]) +fi + +if test -z "$PYTHON_CONFIG"; then + AC_MSG_WARN([No python-config found]) +else + TRY_LINK_PYTHON([`$PYTHON_CONFIG --ldflags`], [`$PYTHON_CONFIG --includes`]) + TRY_LINK_PYTHON([`$PYTHON_CONFIG --ldflags`], [`$PYTHON_CONFIG --cflags`]) + if x$working_python = xno; then + # It seems the library path isn't included on some systems + base=`$PYTHON_CONFIG --prefix` + TRY_LINK_PYTHON([`echo -n -L${base}/lib " "; $PYTHON_CONFIG --ldflags`], [`$PYTHON_CONFIG --includes`]) + TRY_LINK_PYTHON([`echo -n -L${base}/lib " "; $PYTHON_CONFIG --ldflags`], [`$PYTHON_CONFIG --cflags`]) + fi +fi + +if test x$PYTHON != x +then + DISTUTILS_CFLAGS=`$PYTHON -c "from distutils import sysconfig; print '-I%s -I%s %s' % (sysconfig.get_python_inc(), sysconfig.get_python_inc(plat_specific=1), sysconfig.get_config_var('CFLAGS'))"` + DISTUTILS_LDFLAGS=`$PYTHON -c "from distutils import sysconfig; print '%s %s -lpython%s -L%s' % (sysconfig.get_config_var('LIBS'), sysconfig.get_config_var('SYSLIBS'), sysconfig.get_config_var('VERSION'), sysconfig.get_config_var('LIBPL'))"` + TRY_LINK_PYTHON($DISTUTILS_LDFLAGS, $DISTUTILS_CFLAGS) +fi + +SMB_EXT_LIB(EXT_LIB_PYTHON, [$PYTHON_LDFLAGS], [$PYTHON_CFLAGS]) + +AC_MSG_CHECKING(working python module support) +if test $working_python = yes; then + SMB_ENABLE(EXT_LIB_PYTHON,YES) + SMB_ENABLE(LIBPYTHON,YES) + AC_MSG_RESULT([yes]) +else + AC_MSG_ERROR([Python not found. Please install Python 2.x and its development headers/libraries.]) +fi + +AC_MSG_CHECKING(python library directory) +pythondir=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_lib(1, 0, '\\${prefix}')"` +AC_MSG_RESULT($pythondir) + +AC_SUBST(pythondir) diff --git a/source4/scripting/python/config.mk b/source4/scripting/python/config.mk new file mode 100644 index 0000000000..b494ee6e8d --- /dev/null +++ b/source4/scripting/python/config.mk @@ -0,0 +1,37 @@ +[SUBSYSTEM::LIBPYTHON] +PUBLIC_DEPENDENCIES = EXT_LIB_PYTHON +PRIVATE_DEPENDENCIES = PYTALLOC +INIT_FUNCTION_SENTINEL = { NULL, NULL } + +LIBPYTHON_OBJ_FILES = $(addprefix $(pyscriptsrcdir)/, modules.o) + +[SUBSYSTEM::PYTALLOC] +PUBLIC_DEPENDENCIES = EXT_LIB_PYTHON LIBTALLOC + +PYTALLOC_OBJ_FILES = $(addprefix $(pyscriptsrcdir)/, pytalloc.o) + +[PYTHON::python_uuid] +PRIVATE_DEPENDENCIES = LIBNDR + +python_uuid_OBJ_FILES = $(pyscriptsrcdir)/uuidmodule.o + +[PYTHON::python_misc] +LIBRARY_REALNAME = samba/_misc.$(SHLIBEXT) +PRIVATE_DEPENDENCIES = LIBNDR LIBLDB SAMDB CREDENTIALS + +python_misc_OBJ_FILES = $(pyscriptsrcdir)/misc_wrap.o + +$(python_misc_OBJ_FILES): CFLAGS+=$(CFLAG_NO_UNUSED_MACROS) $(CFLAG_NO_CAST_QUAL) + +_PY_FILES = $(shell find $(pyscriptsrcdir)/samba $(pyscriptsrcdir)/subunit -name "*.py") + +$(foreach pyfile, $(_PY_FILES),$(eval $(call python_py_module_template,$(patsubst $(pyscriptsrcdir)/%,%,$(pyfile)),$(pyfile)))) + +$(eval $(call python_py_module_template,samba/misc.py,$(pyscriptsrcdir)/misc.py)) + +EPYDOC_OPTIONS = --no-private --url http://www.samba.org/ --no-sourcecode + +epydoc:: pythonmods + PYTHONPATH=$(pythonbuilddir) epydoc $(EPYDOC_OPTIONS) samba tdb ldb subunit + +install:: installpython diff --git a/source4/scripting/python/examples/netbios.py b/source4/scripting/python/examples/netbios.py new file mode 100644 index 0000000000..3671076a59 --- /dev/null +++ b/source4/scripting/python/examples/netbios.py @@ -0,0 +1,28 @@ +#!/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/>. +# + +from samba.netbios import Node + +n = Node() +(reply_from, names, addresses) = n.query_name("GANIEDA", "192.168.4.0", + timeout=4) + +print "Received reply from %s:" % (reply_from, ) +print "Names: %r" % (names, ) +print "Addresses: %r" % (addresses, ) diff --git a/source4/scripting/python/examples/samr.py b/source4/scripting/python/examples/samr.py new file mode 100755 index 0000000000..1f2afbe688 --- /dev/null +++ b/source4/scripting/python/examples/samr.py @@ -0,0 +1,114 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Unix SMB/CIFS implementation. +# Copyright © Jelmer Vernooij <jelmer@samba.org> 2008 +# +# Based on samr.js © Andrew Tridgell <tridge@samba.org> +# +# 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 + +sys.path.insert(0, "bin/python") + +from samba.dcerpc import samr, security, lsa + +def FillUserInfo(samr, dom_handle, users, level): + """fill a user array with user information from samrQueryUserInfo""" + for i in range(len(users)): + user_handle = samr.OpenUser(handle, security.SEC_FLAG_MAXIMUM_ALLOWED, users[i].idx) + info = samr.QueryUserInfo(user_handle, level) + info.name = users[i].name + info.idx = users[i].idx + users[i] = info + samr.Close(user_handle) + +def toArray((handle, array, num_entries)): + ret = [] + for x in range(num_entries): + ret.append((array.entries[x].idx, array.entries[x].name)) + return ret + + +def test_Connect(samr): + """test the samr_Connect interface""" + print "Testing samr_Connect" + return samr.Connect2(None, security.SEC_FLAG_MAXIMUM_ALLOWED) + +def test_LookupDomain(samr, handle, domain): + """test the samr_LookupDomain interface""" + print "Testing samr_LookupDomain" + return samr.LookupDomain(handle, domain) + +def test_OpenDomain(samr, handle, sid): + """test the samr_OpenDomain interface""" + print "Testing samr_OpenDomain" + return samr.OpenDomain(handle, security.SEC_FLAG_MAXIMUM_ALLOWED, sid) + +def test_EnumDomainUsers(samr, dom_handle): + """test the samr_EnumDomainUsers interface""" + print "Testing samr_EnumDomainUsers" + users = toArray(samr.EnumDomainUsers(dom_handle, 0, 0, -1)) + print "Found %d users" % len(users) + for idx, user in users: + print "\t%s\t(%d)" % (user, idx) + +def test_EnumDomainGroups(samr, dom_handle): + """test the samr_EnumDomainGroups interface""" + print "Testing samr_EnumDomainGroups" + groups = toArray(samr.EnumDomainGroups(dom_handle, 0, 0)) + print "Found %d groups" % len(groups) + for idx, group in groups: + print "\t%s\t(%d)" % (group, idx) + +def test_domain_ops(samr, dom_handle): + """test domain specific ops""" + test_EnumDomainUsers(samr, dom_handle) + test_EnumDomainGroups(samr, dom_handle) + +def test_EnumDomains(samr, handle): + """test the samr_EnumDomains interface""" + print "Testing samr_EnumDomains" + + domains = toArray(samr.EnumDomains(handle, 0, -1)) + print "Found %d domains" % len(domains) + for idx, domain in domains: + print "\t%s (%d)" % (domain, idx) + for idx, domain in domains: + print "Testing domain %s" % domain + sid = samr.LookupDomain(handle, domain) + dom_handle = test_OpenDomain(samr, handle, sid) + test_domain_ops(samr, dom_handle) + samr.Close(dom_handle) + +if len(sys.argv) != 2: + print "Usage: samr.js <BINDING>" + sys.exit(1) + +binding = sys.argv[1] + +print "Connecting to %s" % binding +try: + samr = samr.samr(binding) +except Exception, e: + print "Failed to connect to %s: %s" % (binding, e.message) + sys.exit(1) + +handle = test_Connect(samr) +test_EnumDomains(samr, handle) +samr.Close(handle) + +print "All OK" diff --git a/source4/scripting/python/examples/winreg.py b/source4/scripting/python/examples/winreg.py new file mode 100755 index 0000000000..80b48ecfd7 --- /dev/null +++ b/source4/scripting/python/examples/winreg.py @@ -0,0 +1,87 @@ +#!/usr/bin/python +# +# tool to manipulate a remote registry +# Copyright Andrew Tridgell 2005 +# Copyright Jelmer Vernooij 2007 +# Released under the GNU GPL v3 or later +# + +import sys + +# Find right directory when running from source tree +sys.path.insert(0, "bin/python") + +from samba.dcerpc import winreg +import optparse +import samba.getopt as options + +parser = optparse.OptionParser("%s <BINDING> [path]" % sys.argv[0]) +sambaopts = options.SambaOptions(parser) +parser.add_option_group(sambaopts) +parser.add_option("--createkey", type="string", metavar="KEYNAME", + help="create a key") + +opts, args = parser.parse_args() + +if len(args) < 1: + parser.print_usage() + sys.exit(-1) + +binding = args[0] + +print "Connecting to " + binding +conn = winreg.winreg(binding, sambaopts.get_loadparm()) + +def list_values(key): + (num_values, max_valnamelen, max_valbufsize) = conn.QueryInfoKey(key, winreg.String())[4:8] + for i in range(num_values): + name = winreg.StringBuf() + name.size = max_valnamelen + (name, type, data, _, data_len) = conn.EnumValue(key, i, name, 0, "", max_valbufsize, 0) + print "\ttype=%-30s size=%4d '%s'" % type, len, name + if type in (winreg.REG_SZ, winreg.REG_EXPAND_SZ): + print "\t\t'%s'" % data +# if (v.type == reg.REG_MULTI_SZ) { +# for (j in v.value) { +# printf("\t\t'%s'\n", v.value[j]) +# } +# } +# if (v.type == reg.REG_DWORD || v.type == reg.REG_DWORD_BIG_ENDIAN) { +# printf("\t\t0x%08x (%d)\n", v.value, v.value) +# } +# if (v.type == reg.REG_QWORD) { +# printf("\t\t0x%llx (%lld)\n", v.value, v.value) +# } + +def list_path(key, path): + count = 0 + (num_subkeys, max_subkeylen, max_subkeysize) = conn.QueryInfoKey(key, winreg.String())[1:4] + for i in range(num_subkeys): + name = winreg.StringBuf() + name.size = max_subkeysize + keyclass = winreg.StringBuf() + keyclass.size = max_subkeysize + (name, _, _) = conn.EnumKey(key, i, name, keyclass=keyclass, last_changed_time=None)[0] + subkey = conn.OpenKey(key, name, 0, winreg.KEY_QUERY_VALUE | winreg.KEY_ENUMERATE_SUB_KEYS) + count += list_path(subkey, "%s\\%s" % (path, name)) + list_values(subkey) + return count + +if len(args) > 1: + root = args[1] +else: + root = "HKLM" + +if opts.createkey: + reg.create_key("HKLM\\SOFTWARE", opt.createkey) +else: + print "Listing registry tree '%s'" % root + try: + root_key = getattr(conn, "Open%s" % root)(None, winreg.KEY_QUERY_VALUE | winreg.KEY_ENUMERATE_SUB_KEYS) + except AttributeError: + print "Unknown root key name %s" % root + sys.exit(1) + count = list_path(root_key, root) + if count == 0: + print "No entries found" + sys.exit(1) diff --git a/source4/scripting/python/misc.i b/source4/scripting/python/misc.i new file mode 100644 index 0000000000..81be7d5c16 --- /dev/null +++ b/source4/scripting/python/misc.i @@ -0,0 +1,121 @@ +/* + Unix SMB/CIFS implementation. + 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/>. +*/ + +%module(docstring="Python bindings for miscellaneous Samba functions.",package="samba.misc") misc + +%{ +#include "includes.h" +#include "ldb.h" +#include "param/param.h" +#include "auth/credentials/credentials.h" +#include "dsdb/samdb/samdb.h" +#include "lib/ldb-samba/ldif_handlers.h" +#include "librpc/ndr/libndr.h" +#include "version.h" +%} + +%import "stdint.i" +%include "exception.i" +%import "../../lib/talloc/talloc.i" +%import "../../lib/ldb/ldb.i" +%import "../../auth/credentials/credentials.i" +%import "../../param/param.i" +%import "../../libcli/security/security.i" +%include "../../libcli/util/errors.i" + +%feature("docstring") generate_random_str "S.random_password(len) -> string\n" \ + "Generate random password with specified length."; + +%rename(random_password) generate_random_str; +char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len); + +%feature("docstring") ldb_set_credentials "S.set_credentials(credentials)\n" + "Set credentials to use when connecting."; + +%feature("docstring") ldb_set_session_info "S.set_session_info(session_info)\n" + "Set session info to use when connecting."; + +%feature("docstring") ldb_set_loadparm "S.set_loadparm(session_info)\n" + "Set loadparm context to use when connecting."; + +%inline %{ +void ldb_set_credentials(struct ldb_context *ldb, struct cli_credentials *creds) +{ + ldb_set_opaque(ldb, "credentials", creds); +} + +void ldb_set_session_info(struct ldb_context *ldb, struct auth_session_info *session_info) +{ + ldb_set_opaque(ldb, "sessionInfo", session_info); +} + +void ldb_set_loadparm(struct ldb_context *ldb, struct loadparm_context *lp_ctx) +{ + ldb_set_opaque(ldb, "loadparm", lp_ctx); +} + +%} + +%feature("docstring") samdb_set_domain_sid "S.set_domain_sid(sid)\n" + "Set SID of domain to use."; +bool samdb_set_domain_sid(struct ldb_context *ldb, + const struct dom_sid *dom_sid_in); + +WERROR dsdb_attach_schema_from_ldif_file(struct ldb_context *ldb, const char *pf, const char *df); + +%feature("docstring") version "version()\n" + "Obtain the Samba version."; + +%inline { +const char *version(void) +{ + return SAMBA_VERSION_STRING; +} +} +int dsdb_set_global_schema(struct ldb_context *ldb); +%feature("docstring") ldb_register_samba_handlers "register_samba_handlers()\n" + "Register Samba-specific LDB modules and schemas."; +int ldb_register_samba_handlers(struct ldb_context *ldb); + +%inline %{ +bool dsdb_set_ntds_invocation_id(struct ldb_context *ldb, const char *guid) +{ + struct GUID invocation_id_in; + if (NT_STATUS_IS_ERR(GUID_from_string(guid, &invocation_id_in))) { + return false; + } + return samdb_set_ntds_invocation_id(ldb, &invocation_id_in); +} +%} + +char *private_path(TALLOC_CTX* mem_ctx, struct loadparm_context *lp_ctx, + const char *name); + +typedef unsigned long time_t; + +/* + convert from unix time to NT time +*/ +%inline %{ +uint64_t unix2nttime(time_t t) +{ + NTTIME nt; + unix_to_nt_time(&nt, t); + return (uint64_t)nt; +} +%} diff --git a/source4/scripting/python/misc.py b/source4/scripting/python/misc.py new file mode 100644 index 0000000000..e52d7df11d --- /dev/null +++ b/source4/scripting/python/misc.py @@ -0,0 +1,123 @@ +# This file was automatically generated by SWIG (http://www.swig.org). +# Version 1.3.36 +# +# Don't modify this file, modify the SWIG interface instead. + +""" +Python bindings for miscellaneous Samba functions. +""" + +import _misc +import new +new_instancemethod = new.instancemethod +try: + _swig_property = property +except NameError: + pass # Python < 2.2 doesn't have 'property'. +def _swig_setattr_nondynamic(self,class_type,name,value,static=1): + if (name == "thisown"): return self.this.own(value) + if (name == "this"): + if type(value).__name__ == 'PySwigObject': + self.__dict__[name] = value + return + method = class_type.__swig_setmethods__.get(name,None) + if method: return method(self,value) + if (not static) or hasattr(self,name): + self.__dict__[name] = value + else: + raise AttributeError("You cannot add attributes to %s" % self) + +def _swig_setattr(self,class_type,name,value): + return _swig_setattr_nondynamic(self,class_type,name,value,0) + +def _swig_getattr(self,class_type,name): + if (name == "thisown"): return self.this.own() + method = class_type.__swig_getmethods__.get(name,None) + if method: return method(self) + raise AttributeError,name + +def _swig_repr(self): + try: strthis = "proxy of " + self.this.__repr__() + except: strthis = "" + return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) + +import types +try: + _object = types.ObjectType + _newclass = 1 +except AttributeError: + class _object : pass + _newclass = 0 +del types + + +def _swig_setattr_nondynamic_method(set): + def set_attr(self,name,value): + if (name == "thisown"): return self.this.own(value) + if hasattr(self,name) or (name == "this"): + set(self,name,value) + else: + raise AttributeError("You cannot add attributes to %s" % self) + return set_attr + + +import ldb +import credentials +import param +import security + +def random_password(*args, **kwargs): + """ + S.random_password(len) -> string + Generate random password with specified length. + """ + return _misc.random_password(*args, **kwargs) + +def ldb_set_credentials(*args, **kwargs): + """ + S.set_credentials(credentials) + Set credentials to use when connecting. + """ + return _misc.ldb_set_credentials(*args, **kwargs) + +def ldb_set_session_info(*args, **kwargs): + """ + S.set_session_info(session_info) + Set session info to use when connecting. + """ + return _misc.ldb_set_session_info(*args, **kwargs) + +def ldb_set_loadparm(*args, **kwargs): + """ + S.set_loadparm(session_info) + Set loadparm context to use when connecting. + """ + return _misc.ldb_set_loadparm(*args, **kwargs) + +def samdb_set_domain_sid(*args, **kwargs): + """ + S.set_domain_sid(sid) + Set SID of domain to use. + """ + return _misc.samdb_set_domain_sid(*args, **kwargs) +dsdb_attach_schema_from_ldif_file = _misc.dsdb_attach_schema_from_ldif_file + +def version(*args): + """ + version() + Obtain the Samba version. + """ + return _misc.version(*args) +dsdb_set_global_schema = _misc.dsdb_set_global_schema + +def ldb_register_samba_handlers(*args, **kwargs): + """ + register_samba_handlers() + Register Samba-specific LDB modules and schemas. + """ + return _misc.ldb_register_samba_handlers(*args, **kwargs) +dsdb_set_ntds_invocation_id = _misc.dsdb_set_ntds_invocation_id +private_path = _misc.private_path +unix2nttime = _misc.unix2nttime + + diff --git a/source4/scripting/python/misc_wrap.c b/source4/scripting/python/misc_wrap.c new file mode 100644 index 0000000000..3aee83f72c --- /dev/null +++ b/source4/scripting/python/misc_wrap.c @@ -0,0 +1,3976 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 1.3.36 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +#define SWIGPYTHON +#define SWIG_PYTHON_NO_BUILD_NONE +/* ----------------------------------------------------------------------------- + * This section contains generic SWIG labels for method/variable + * declarations/attributes, and other compiler dependent labels. + * ----------------------------------------------------------------------------- */ + +/* template workaround for compilers that cannot correctly implement the C++ standard */ +#ifndef SWIGTEMPLATEDISAMBIGUATOR +# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) +# define SWIGTEMPLATEDISAMBIGUATOR template +# elif defined(__HP_aCC) +/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ +/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ +# define SWIGTEMPLATEDISAMBIGUATOR template +# else +# define SWIGTEMPLATEDISAMBIGUATOR +# endif +#endif + +/* inline attribute */ +#ifndef SWIGINLINE +# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) +# define SWIGINLINE inline +# else +# define SWIGINLINE +# endif +#endif + +/* attribute recognised by some compilers to avoid 'unused' warnings */ +#ifndef SWIGUNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +# elif defined(__ICC) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +#endif + +#ifndef SWIG_MSC_UNSUPPRESS_4505 +# if defined(_MSC_VER) +# pragma warning(disable : 4505) /* unreferenced local function has been removed */ +# endif +#endif + +#ifndef SWIGUNUSEDPARM +# ifdef __cplusplus +# define SWIGUNUSEDPARM(p) +# else +# define SWIGUNUSEDPARM(p) p SWIGUNUSED +# endif +#endif + +/* internal SWIG method */ +#ifndef SWIGINTERN +# define SWIGINTERN static SWIGUNUSED +#endif + +/* internal inline SWIG method */ +#ifndef SWIGINTERNINLINE +# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE +#endif + +/* exporting methods */ +#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +# ifndef GCC_HASCLASSVISIBILITY +# define GCC_HASCLASSVISIBILITY +# endif +#endif + +#ifndef SWIGEXPORT +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# if defined(STATIC_LINKED) +# define SWIGEXPORT +# else +# define SWIGEXPORT __declspec(dllexport) +# endif +# else +# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) +# define SWIGEXPORT __attribute__ ((visibility("default"))) +# else +# define SWIGEXPORT +# endif +# endif +#endif + +/* calling conventions for Windows */ +#ifndef SWIGSTDCALL +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# define SWIGSTDCALL __stdcall +# else +# define SWIGSTDCALL +# endif +#endif + +/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ +#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +# define _CRT_SECURE_NO_DEPRECATE +#endif + +/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ +#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) +# define _SCL_SECURE_NO_DEPRECATE +#endif + + + +/* Python.h has to appear first */ +#include <Python.h> + +/* ----------------------------------------------------------------------------- + * swigrun.swg + * + * This file contains generic CAPI SWIG runtime support for pointer + * type checking. + * ----------------------------------------------------------------------------- */ + +/* This should only be incremented when either the layout of swig_type_info changes, + or for whatever reason, the runtime changes incompatibly */ +#define SWIG_RUNTIME_VERSION "4" + +/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */ +#ifdef SWIG_TYPE_TABLE +# define SWIG_QUOTE_STRING(x) #x +# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x) +# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE) +#else +# define SWIG_TYPE_TABLE_NAME +#endif + +/* + You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for + creating a static or dynamic library from the swig runtime code. + In 99.9% of the cases, swig just needs to declare them as 'static'. + + But only do this if is strictly necessary, ie, if you have problems + with your compiler or so. +*/ + +#ifndef SWIGRUNTIME +# define SWIGRUNTIME SWIGINTERN +#endif + +#ifndef SWIGRUNTIMEINLINE +# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE +#endif + +/* Generic buffer size */ +#ifndef SWIG_BUFFER_SIZE +# define SWIG_BUFFER_SIZE 1024 +#endif + +/* Flags for pointer conversions */ +#define SWIG_POINTER_DISOWN 0x1 +#define SWIG_CAST_NEW_MEMORY 0x2 + +/* Flags for new pointer objects */ +#define SWIG_POINTER_OWN 0x1 + + +/* + Flags/methods for returning states. + + The swig conversion methods, as ConvertPtr, return and integer + that tells if the conversion was successful or not. And if not, + an error code can be returned (see swigerrors.swg for the codes). + + Use the following macros/flags to set or process the returning + states. + + In old swig versions, you usually write code as: + + if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) { + // success code + } else { + //fail code + } + + Now you can be more explicit as: + + int res = SWIG_ConvertPtr(obj,vptr,ty.flags); + if (SWIG_IsOK(res)) { + // success code + } else { + // fail code + } + + that seems to be the same, but now you can also do + + Type *ptr; + int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags); + if (SWIG_IsOK(res)) { + // success code + if (SWIG_IsNewObj(res) { + ... + delete *ptr; + } else { + ... + } + } else { + // fail code + } + + I.e., now SWIG_ConvertPtr can return new objects and you can + identify the case and take care of the deallocation. Of course that + requires also to SWIG_ConvertPtr to return new result values, as + + int SWIG_ConvertPtr(obj, ptr,...) { + if (<obj is ok>) { + if (<need new object>) { + *ptr = <ptr to new allocated object>; + return SWIG_NEWOBJ; + } else { + *ptr = <ptr to old object>; + return SWIG_OLDOBJ; + } + } else { + return SWIG_BADOBJ; + } + } + + Of course, returning the plain '0(success)/-1(fail)' still works, but you can be + more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the + swig errors code. + + Finally, if the SWIG_CASTRANK_MODE is enabled, the result code + allows to return the 'cast rank', for example, if you have this + + int food(double) + int fooi(int); + + and you call + + food(1) // cast rank '1' (1 -> 1.0) + fooi(1) // cast rank '0' + + just use the SWIG_AddCast()/SWIG_CheckState() + + + */ +#define SWIG_OK (0) +#define SWIG_ERROR (-1) +#define SWIG_IsOK(r) (r >= 0) +#define SWIG_ArgError(r) ((r != SWIG_ERROR) ? r : SWIG_TypeError) + +/* The CastRankLimit says how many bits are used for the cast rank */ +#define SWIG_CASTRANKLIMIT (1 << 8) +/* The NewMask denotes the object was created (using new/malloc) */ +#define SWIG_NEWOBJMASK (SWIG_CASTRANKLIMIT << 1) +/* The TmpMask is for in/out typemaps that use temporal objects */ +#define SWIG_TMPOBJMASK (SWIG_NEWOBJMASK << 1) +/* Simple returning values */ +#define SWIG_BADOBJ (SWIG_ERROR) +#define SWIG_OLDOBJ (SWIG_OK) +#define SWIG_NEWOBJ (SWIG_OK | SWIG_NEWOBJMASK) +#define SWIG_TMPOBJ (SWIG_OK | SWIG_TMPOBJMASK) +/* Check, add and del mask methods */ +#define SWIG_AddNewMask(r) (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r) +#define SWIG_DelNewMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r) +#define SWIG_IsNewObj(r) (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK)) +#define SWIG_AddTmpMask(r) (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r) +#define SWIG_DelTmpMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r) +#define SWIG_IsTmpObj(r) (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK)) + + +/* Cast-Rank Mode */ +#if defined(SWIG_CASTRANK_MODE) +# ifndef SWIG_TypeRank +# define SWIG_TypeRank unsigned long +# endif +# ifndef SWIG_MAXCASTRANK /* Default cast allowed */ +# define SWIG_MAXCASTRANK (2) +# endif +# define SWIG_CASTRANKMASK ((SWIG_CASTRANKLIMIT) -1) +# define SWIG_CastRank(r) (r & SWIG_CASTRANKMASK) +SWIGINTERNINLINE int SWIG_AddCast(int r) { + return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r; +} +SWIGINTERNINLINE int SWIG_CheckState(int r) { + return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; +} +#else /* no cast-rank mode */ +# define SWIG_AddCast +# define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0) +#endif + + + + +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *(*swig_converter_func)(void *, int *); +typedef struct swig_type_info *(*swig_dycast_func)(void **); + +/* Structure to store information on one type */ +typedef struct swig_type_info { + const char *name; /* mangled name of this type */ + const char *str; /* human readable name of this type */ + swig_dycast_func dcast; /* dynamic cast function down a hierarchy */ + struct swig_cast_info *cast; /* linked list of types that can cast into this type */ + void *clientdata; /* language specific type data */ + int owndata; /* flag if the structure owns the clientdata */ +} swig_type_info; + +/* Structure to store a type and conversion function used for casting */ +typedef struct swig_cast_info { + swig_type_info *type; /* pointer to type that is equivalent to this type */ + swig_converter_func converter; /* function to cast the void pointers */ + struct swig_cast_info *next; /* pointer to next cast in linked list */ + struct swig_cast_info *prev; /* pointer to the previous cast */ +} swig_cast_info; + +/* Structure used to store module information + * Each module generates one structure like this, and the runtime collects + * all of these structures and stores them in a circularly linked list.*/ +typedef struct swig_module_info { + swig_type_info **types; /* Array of pointers to swig_type_info structures that are in this module */ + size_t size; /* Number of types in this module */ + struct swig_module_info *next; /* Pointer to next element in circularly linked list */ + swig_type_info **type_initial; /* Array of initially generated type structures */ + swig_cast_info **cast_initial; /* Array of initially generated casting structures */ + void *clientdata; /* Language specific module data */ +} swig_module_info; + +/* + Compare two type names skipping the space characters, therefore + "char*" == "char *" and "Class<int>" == "Class<int >", etc. + + Return 0 when the two name types are equivalent, as in + strncmp, but skipping ' '. +*/ +SWIGRUNTIME int +SWIG_TypeNameComp(const char *f1, const char *l1, + const char *f2, const char *l2) { + for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) { + while ((*f1 == ' ') && (f1 != l1)) ++f1; + while ((*f2 == ' ') && (f2 != l2)) ++f2; + if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1; + } + return (int)((l1 - f1) - (l2 - f2)); +} + +/* + Check type equivalence in a name list like <name1>|<name2>|... + Return 0 if not equal, 1 if equal +*/ +SWIGRUNTIME int +SWIG_TypeEquiv(const char *nb, const char *tb) { + int equiv = 0; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (!equiv && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0; + if (*ne) ++ne; + } + return equiv; +} + +/* + Check type equivalence in a name list like <name1>|<name2>|... + Return 0 if equal, -1 if nb < tb, 1 if nb > tb +*/ +SWIGRUNTIME int +SWIG_TypeCompare(const char *nb, const char *tb) { + int equiv = 0; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (!equiv && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0; + if (*ne) ++ne; + } + return equiv; +} + + +/* think of this as a c++ template<> or a scheme macro */ +#define SWIG_TypeCheck_Template(comparison, ty) \ + if (ty) { \ + swig_cast_info *iter = ty->cast; \ + while (iter) { \ + if (comparison) { \ + if (iter == ty->cast) return iter; \ + /* Move iter to the top of the linked list */ \ + iter->prev->next = iter->next; \ + if (iter->next) \ + iter->next->prev = iter->prev; \ + iter->next = ty->cast; \ + iter->prev = 0; \ + if (ty->cast) ty->cast->prev = iter; \ + ty->cast = iter; \ + return iter; \ + } \ + iter = iter->next; \ + } \ + } \ + return 0 + +/* + Check the typename +*/ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheck(const char *c, swig_type_info *ty) { + SWIG_TypeCheck_Template(strcmp(iter->type->name, c) == 0, ty); +} + +/* Same as previous function, except strcmp is replaced with a pointer comparison */ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *into) { + SWIG_TypeCheck_Template(iter->type == from, into); +} + +/* + Cast a pointer up an inheritance hierarchy +*/ +SWIGRUNTIMEINLINE void * +SWIG_TypeCast(swig_cast_info *ty, void *ptr, int *newmemory) { + return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr, newmemory); +} + +/* + Dynamic pointer casting. Down an inheritance hierarchy +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) { + swig_type_info *lastty = ty; + if (!ty || !ty->dcast) return ty; + while (ty && (ty->dcast)) { + ty = (*ty->dcast)(ptr); + if (ty) lastty = ty; + } + return lastty; +} + +/* + Return the name associated with this type +*/ +SWIGRUNTIMEINLINE const char * +SWIG_TypeName(const swig_type_info *ty) { + return ty->name; +} + +/* + Return the pretty name associated with this type, + that is an unmangled type name in a form presentable to the user. +*/ +SWIGRUNTIME const char * +SWIG_TypePrettyName(const swig_type_info *type) { + /* The "str" field contains the equivalent pretty names of the + type, separated by vertical-bar characters. We choose + to print the last name, as it is often (?) the most + specific. */ + if (!type) return NULL; + if (type->str != NULL) { + const char *last_name = type->str; + const char *s; + for (s = type->str; *s; s++) + if (*s == '|') last_name = s+1; + return last_name; + } + else + return type->name; +} + +/* + Set the clientdata field for a type +*/ +SWIGRUNTIME void +SWIG_TypeClientData(swig_type_info *ti, void *clientdata) { + swig_cast_info *cast = ti->cast; + /* if (ti->clientdata == clientdata) return; */ + ti->clientdata = clientdata; + + while (cast) { + if (!cast->converter) { + swig_type_info *tc = cast->type; + if (!tc->clientdata) { + SWIG_TypeClientData(tc, clientdata); + } + } + cast = cast->next; + } +} +SWIGRUNTIME void +SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) { + SWIG_TypeClientData(ti, clientdata); + ti->owndata = 1; +} + +/* + Search for a swig_type_info structure only by mangled name + Search is a O(log #types) + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_MangledTypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + swig_module_info *iter = start; + do { + if (iter->size) { + register size_t l = 0; + register size_t r = iter->size - 1; + do { + /* since l+r >= 0, we can (>> 1) instead (/ 2) */ + register size_t i = (l + r) >> 1; + const char *iname = iter->types[i]->name; + if (iname) { + register int compare = strcmp(name, iname); + if (compare == 0) { + return iter->types[i]; + } else if (compare < 0) { + if (i) { + r = i - 1; + } else { + break; + } + } else if (compare > 0) { + l = i + 1; + } + } else { + break; /* should never happen */ + } + } while (l <= r); + } + iter = iter->next; + } while (iter != end); + return 0; +} + +/* + Search for a swig_type_info structure for either a mangled name or a human readable name. + It first searches the mangled names of the types, which is a O(log #types) + If a type is not found it then searches the human readable names, which is O(#types). + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + /* STEP 1: Search the name field using binary search */ + swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name); + if (ret) { + return ret; + } else { + /* STEP 2: If the type hasn't been found, do a complete search + of the str field (the human readable name) */ + swig_module_info *iter = start; + do { + register size_t i = 0; + for (; i < iter->size; ++i) { + if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name))) + return iter->types[i]; + } + iter = iter->next; + } while (iter != end); + } + + /* neither found a match */ + return 0; +} + +/* + Pack binary data into a string +*/ +SWIGRUNTIME char * +SWIG_PackData(char *c, void *ptr, size_t sz) { + static const char hex[17] = "0123456789abcdef"; + register const unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register unsigned char uu = *u; + *(c++) = hex[(uu & 0xf0) >> 4]; + *(c++) = hex[uu & 0xf]; + } + return c; +} + +/* + Unpack binary data from a string +*/ +SWIGRUNTIME const char * +SWIG_UnpackData(const char *c, void *ptr, size_t sz) { + register unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register char d = *(c++); + register unsigned char uu; + if ((d >= '0') && (d <= '9')) + uu = ((d - '0') << 4); + else if ((d >= 'a') && (d <= 'f')) + uu = ((d - ('a'-10)) << 4); + else + return (char *) 0; + d = *(c++); + if ((d >= '0') && (d <= '9')) + uu |= (d - '0'); + else if ((d >= 'a') && (d <= 'f')) + uu |= (d - ('a'-10)); + else + return (char *) 0; + *u = uu; + } + return c; +} + +/* + Pack 'void *' into a string buffer. +*/ +SWIGRUNTIME char * +SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) { + char *r = buff; + if ((2*sizeof(void *) + 2) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,&ptr,sizeof(void *)); + if (strlen(name) + 1 > (bsz - (r - buff))) return 0; + strcpy(r,name); + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + *ptr = (void *) 0; + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sizeof(void *)); +} + +SWIGRUNTIME char * +SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) { + char *r = buff; + size_t lname = (name ? strlen(name) : 0); + if ((2*sz + 2 + lname) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,ptr,sz); + if (lname) { + strncpy(r,name,lname+1); + } else { + *r = 0; + } + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + memset(ptr,0,sz); + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sz); +} + +#ifdef __cplusplus +} +#endif + +/* Errors in SWIG */ +#define SWIG_UnknownError -1 +#define SWIG_IOError -2 +#define SWIG_RuntimeError -3 +#define SWIG_IndexError -4 +#define SWIG_TypeError -5 +#define SWIG_DivisionByZero -6 +#define SWIG_OverflowError -7 +#define SWIG_SyntaxError -8 +#define SWIG_ValueError -9 +#define SWIG_SystemError -10 +#define SWIG_AttributeError -11 +#define SWIG_MemoryError -12 +#define SWIG_NullReferenceError -13 + + + + +/* Add PyOS_snprintf for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 +# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# define PyOS_snprintf _snprintf +# else +# define PyOS_snprintf snprintf +# endif +#endif + +/* A crude PyString_FromFormat implementation for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 + +#ifndef SWIG_PYBUFFER_SIZE +# define SWIG_PYBUFFER_SIZE 1024 +#endif + +static PyObject * +PyString_FromFormat(const char *fmt, ...) { + va_list ap; + char buf[SWIG_PYBUFFER_SIZE * 2]; + int res; + va_start(ap, fmt); + res = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return (res < 0 || res >= (int)sizeof(buf)) ? 0 : PyString_FromString(buf); +} +#endif + +/* Add PyObject_Del for old Pythons */ +#if PY_VERSION_HEX < 0x01060000 +# define PyObject_Del(op) PyMem_DEL((op)) +#endif +#ifndef PyObject_DEL +# define PyObject_DEL PyObject_Del +#endif + +/* A crude PyExc_StopIteration exception for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 +# ifndef PyExc_StopIteration +# define PyExc_StopIteration PyExc_RuntimeError +# endif +# ifndef PyObject_GenericGetAttr +# define PyObject_GenericGetAttr 0 +# endif +#endif +/* Py_NotImplemented is defined in 2.1 and up. */ +#if PY_VERSION_HEX < 0x02010000 +# ifndef Py_NotImplemented +# define Py_NotImplemented PyExc_RuntimeError +# endif +#endif + + +/* A crude PyString_AsStringAndSize implementation for old Pythons */ +#if PY_VERSION_HEX < 0x02010000 +# ifndef PyString_AsStringAndSize +# define PyString_AsStringAndSize(obj, s, len) {*s = PyString_AsString(obj); *len = *s ? strlen(*s) : 0;} +# endif +#endif + +/* PySequence_Size for old Pythons */ +#if PY_VERSION_HEX < 0x02000000 +# ifndef PySequence_Size +# define PySequence_Size PySequence_Length +# endif +#endif + + +/* PyBool_FromLong for old Pythons */ +#if PY_VERSION_HEX < 0x02030000 +static +PyObject *PyBool_FromLong(long ok) +{ + PyObject *result = ok ? Py_True : Py_False; + Py_INCREF(result); + return result; +} +#endif + +/* Py_ssize_t for old Pythons */ +/* This code is as recommended by: */ +/* http://www.python.org/dev/peps/pep-0353/#conversion-guidelines */ +#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) +typedef int Py_ssize_t; +# define PY_SSIZE_T_MAX INT_MAX +# define PY_SSIZE_T_MIN INT_MIN +#endif + +/* ----------------------------------------------------------------------------- + * error manipulation + * ----------------------------------------------------------------------------- */ + +SWIGRUNTIME PyObject* +SWIG_Python_ErrorType(int code) { + PyObject* type = 0; + switch(code) { + case SWIG_MemoryError: + type = PyExc_MemoryError; + break; + case SWIG_IOError: + type = PyExc_IOError; + break; + case SWIG_RuntimeError: + type = PyExc_RuntimeError; + break; + case SWIG_IndexError: + type = PyExc_IndexError; + break; + case SWIG_TypeError: + type = PyExc_TypeError; + break; + case SWIG_DivisionByZero: + type = PyExc_ZeroDivisionError; + break; + case SWIG_OverflowError: + type = PyExc_OverflowError; + break; + case SWIG_SyntaxError: + type = PyExc_SyntaxError; + break; + case SWIG_ValueError: + type = PyExc_ValueError; + break; + case SWIG_SystemError: + type = PyExc_SystemError; + break; + case SWIG_AttributeError: + type = PyExc_AttributeError; + break; + default: + type = PyExc_RuntimeError; + } + return type; +} + + +SWIGRUNTIME void +SWIG_Python_AddErrorMsg(const char* mesg) +{ + PyObject *type = 0; + PyObject *value = 0; + PyObject *traceback = 0; + + if (PyErr_Occurred()) PyErr_Fetch(&type, &value, &traceback); + if (value) { + PyObject *old_str = PyObject_Str(value); + PyErr_Clear(); + Py_XINCREF(type); + PyErr_Format(type, "%s %s", PyString_AsString(old_str), mesg); + Py_DECREF(old_str); + Py_DECREF(value); + } else { + PyErr_SetString(PyExc_RuntimeError, mesg); + } +} + + + +#if defined(SWIG_PYTHON_NO_THREADS) +# if defined(SWIG_PYTHON_THREADS) +# undef SWIG_PYTHON_THREADS +# endif +#endif +#if defined(SWIG_PYTHON_THREADS) /* Threading support is enabled */ +# if !defined(SWIG_PYTHON_USE_GIL) && !defined(SWIG_PYTHON_NO_USE_GIL) +# if (PY_VERSION_HEX >= 0x02030000) /* For 2.3 or later, use the PyGILState calls */ +# define SWIG_PYTHON_USE_GIL +# endif +# endif +# if defined(SWIG_PYTHON_USE_GIL) /* Use PyGILState threads calls */ +# ifndef SWIG_PYTHON_INITIALIZE_THREADS +# define SWIG_PYTHON_INITIALIZE_THREADS PyEval_InitThreads() +# endif +# ifdef __cplusplus /* C++ code */ + class SWIG_Python_Thread_Block { + bool status; + PyGILState_STATE state; + public: + void end() { if (status) { PyGILState_Release(state); status = false;} } + SWIG_Python_Thread_Block() : status(true), state(PyGILState_Ensure()) {} + ~SWIG_Python_Thread_Block() { end(); } + }; + class SWIG_Python_Thread_Allow { + bool status; + PyThreadState *save; + public: + void end() { if (status) { PyEval_RestoreThread(save); status = false; }} + SWIG_Python_Thread_Allow() : status(true), save(PyEval_SaveThread()) {} + ~SWIG_Python_Thread_Allow() { end(); } + }; +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK SWIG_Python_Thread_Block _swig_thread_block +# define SWIG_PYTHON_THREAD_END_BLOCK _swig_thread_block.end() +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW SWIG_Python_Thread_Allow _swig_thread_allow +# define SWIG_PYTHON_THREAD_END_ALLOW _swig_thread_allow.end() +# else /* C code */ +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK PyGILState_STATE _swig_thread_block = PyGILState_Ensure() +# define SWIG_PYTHON_THREAD_END_BLOCK PyGILState_Release(_swig_thread_block) +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW PyThreadState *_swig_thread_allow = PyEval_SaveThread() +# define SWIG_PYTHON_THREAD_END_ALLOW PyEval_RestoreThread(_swig_thread_allow) +# endif +# else /* Old thread way, not implemented, user must provide it */ +# if !defined(SWIG_PYTHON_INITIALIZE_THREADS) +# define SWIG_PYTHON_INITIALIZE_THREADS +# endif +# if !defined(SWIG_PYTHON_THREAD_BEGIN_BLOCK) +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK +# endif +# if !defined(SWIG_PYTHON_THREAD_END_BLOCK) +# define SWIG_PYTHON_THREAD_END_BLOCK +# endif +# if !defined(SWIG_PYTHON_THREAD_BEGIN_ALLOW) +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW +# endif +# if !defined(SWIG_PYTHON_THREAD_END_ALLOW) +# define SWIG_PYTHON_THREAD_END_ALLOW +# endif +# endif +#else /* No thread support */ +# define SWIG_PYTHON_INITIALIZE_THREADS +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK +# define SWIG_PYTHON_THREAD_END_BLOCK +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW +# define SWIG_PYTHON_THREAD_END_ALLOW +#endif + +/* ----------------------------------------------------------------------------- + * Python API portion that goes into the runtime + * ----------------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* cc-mode */ +#endif +#endif + +/* ----------------------------------------------------------------------------- + * Constant declarations + * ----------------------------------------------------------------------------- */ + +/* Constant Types */ +#define SWIG_PY_POINTER 4 +#define SWIG_PY_BINARY 5 + +/* Constant information structure */ +typedef struct swig_const_info { + int type; + char *name; + long lvalue; + double dvalue; + void *pvalue; + swig_type_info **ptype; +} swig_const_info; + +#ifdef __cplusplus +#if 0 +{ /* cc-mode */ +#endif +} +#endif + + +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * pyrun.swg + * + * This file contains the runtime support for Python modules + * and includes code for managing global variables and pointer + * type checking. + * + * ----------------------------------------------------------------------------- */ + +/* Common SWIG API */ + +/* for raw pointers */ +#define SWIG_Python_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, 0) +#define SWIG_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtr(obj, pptr, type, flags) +#define SWIG_ConvertPtrAndOwn(obj,pptr,type,flags,own) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, own) +#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(ptr, type, flags) +#define SWIG_CheckImplicit(ty) SWIG_Python_CheckImplicit(ty) +#define SWIG_AcquirePtr(ptr, src) SWIG_Python_AcquirePtr(ptr, src) +#define swig_owntype int + +/* for raw packed data */ +#define SWIG_ConvertPacked(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewPackedObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) + +/* for class or struct pointers */ +#define SWIG_ConvertInstance(obj, pptr, type, flags) SWIG_ConvertPtr(obj, pptr, type, flags) +#define SWIG_NewInstanceObj(ptr, type, flags) SWIG_NewPointerObj(ptr, type, flags) + +/* for C or C++ function pointers */ +#define SWIG_ConvertFunctionPtr(obj, pptr, type) SWIG_Python_ConvertFunctionPtr(obj, pptr, type) +#define SWIG_NewFunctionPtrObj(ptr, type) SWIG_Python_NewPointerObj(ptr, type, 0) + +/* for C++ member pointers, ie, member methods */ +#define SWIG_ConvertMember(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewMemberObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) + + +/* Runtime API */ + +#define SWIG_GetModule(clientdata) SWIG_Python_GetModule() +#define SWIG_SetModule(clientdata, pointer) SWIG_Python_SetModule(pointer) +#define SWIG_NewClientData(obj) PySwigClientData_New(obj) + +#define SWIG_SetErrorObj SWIG_Python_SetErrorObj +#define SWIG_SetErrorMsg SWIG_Python_SetErrorMsg +#define SWIG_ErrorType(code) SWIG_Python_ErrorType(code) +#define SWIG_Error(code, msg) SWIG_Python_SetErrorMsg(SWIG_ErrorType(code), msg) +#define SWIG_fail goto fail + + +/* Runtime API implementation */ + +/* Error manipulation */ + +SWIGINTERN void +SWIG_Python_SetErrorObj(PyObject *errtype, PyObject *obj) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyErr_SetObject(errtype, obj); + Py_DECREF(obj); + SWIG_PYTHON_THREAD_END_BLOCK; +} + +SWIGINTERN void +SWIG_Python_SetErrorMsg(PyObject *errtype, const char *msg) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyErr_SetString(errtype, (char *) msg); + SWIG_PYTHON_THREAD_END_BLOCK; +} + +#define SWIG_Python_Raise(obj, type, desc) SWIG_Python_SetErrorObj(SWIG_Python_ExceptionType(desc), obj) + +/* Set a constant value */ + +SWIGINTERN void +SWIG_Python_SetConstant(PyObject *d, const char *name, PyObject *obj) { + PyDict_SetItemString(d, (char*) name, obj); + Py_DECREF(obj); +} + +/* Append a value to the result obj */ + +SWIGINTERN PyObject* +SWIG_Python_AppendOutput(PyObject* result, PyObject* obj) { +#if !defined(SWIG_PYTHON_OUTPUT_TUPLE) + if (!result) { + result = obj; + } else if (result == Py_None) { + Py_DECREF(result); + result = obj; + } else { + if (!PyList_Check(result)) { + PyObject *o2 = result; + result = PyList_New(1); + PyList_SetItem(result, 0, o2); + } + PyList_Append(result,obj); + Py_DECREF(obj); + } + return result; +#else + PyObject* o2; + PyObject* o3; + if (!result) { + result = obj; + } else if (result == Py_None) { + Py_DECREF(result); + result = obj; + } else { + if (!PyTuple_Check(result)) { + o2 = result; + result = PyTuple_New(1); + PyTuple_SET_ITEM(result, 0, o2); + } + o3 = PyTuple_New(1); + PyTuple_SET_ITEM(o3, 0, obj); + o2 = result; + result = PySequence_Concat(o2, o3); + Py_DECREF(o2); + Py_DECREF(o3); + } + return result; +#endif +} + +/* Unpack the argument tuple */ + +SWIGINTERN int +SWIG_Python_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, PyObject **objs) +{ + if (!args) { + if (!min && !max) { + return 1; + } else { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got none", + name, (min == max ? "" : "at least "), (int)min); + return 0; + } + } + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_SystemError, "UnpackTuple() argument list is not a tuple"); + return 0; + } else { + register Py_ssize_t l = PyTuple_GET_SIZE(args); + if (l < min) { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", + name, (min == max ? "" : "at least "), (int)min, (int)l); + return 0; + } else if (l > max) { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", + name, (min == max ? "" : "at most "), (int)max, (int)l); + return 0; + } else { + register int i; + for (i = 0; i < l; ++i) { + objs[i] = PyTuple_GET_ITEM(args, i); + } + for (; l < max; ++l) { + objs[l] = 0; + } + return i + 1; + } + } +} + +/* A functor is a function object with one single object argument */ +#if PY_VERSION_HEX >= 0x02020000 +#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunctionObjArgs(functor, obj, NULL); +#else +#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunction(functor, "O", obj); +#endif + +/* + Helper for static pointer initialization for both C and C++ code, for example + static PyObject *SWIG_STATIC_POINTER(MyVar) = NewSomething(...); +*/ +#ifdef __cplusplus +#define SWIG_STATIC_POINTER(var) var +#else +#define SWIG_STATIC_POINTER(var) var = 0; if (!var) var +#endif + +/* ----------------------------------------------------------------------------- + * Pointer declarations + * ----------------------------------------------------------------------------- */ + +/* Flags for new pointer objects */ +#define SWIG_POINTER_NOSHADOW (SWIG_POINTER_OWN << 1) +#define SWIG_POINTER_NEW (SWIG_POINTER_NOSHADOW | SWIG_POINTER_OWN) + +#define SWIG_POINTER_IMPLICIT_CONV (SWIG_POINTER_DISOWN << 1) + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* cc-mode */ +#endif +#endif + +/* How to access Py_None */ +#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# ifndef SWIG_PYTHON_NO_BUILD_NONE +# ifndef SWIG_PYTHON_BUILD_NONE +# define SWIG_PYTHON_BUILD_NONE +# endif +# endif +#endif + +#ifdef SWIG_PYTHON_BUILD_NONE +# ifdef Py_None +# undef Py_None +# define Py_None SWIG_Py_None() +# endif +SWIGRUNTIMEINLINE PyObject * +_SWIG_Py_None(void) +{ + PyObject *none = Py_BuildValue((char*)""); + Py_DECREF(none); + return none; +} +SWIGRUNTIME PyObject * +SWIG_Py_None(void) +{ + static PyObject *SWIG_STATIC_POINTER(none) = _SWIG_Py_None(); + return none; +} +#endif + +/* The python void return value */ + +SWIGRUNTIMEINLINE PyObject * +SWIG_Py_Void(void) +{ + PyObject *none = Py_None; + Py_INCREF(none); + return none; +} + +/* PySwigClientData */ + +typedef struct { + PyObject *klass; + PyObject *newraw; + PyObject *newargs; + PyObject *destroy; + int delargs; + int implicitconv; +} PySwigClientData; + +SWIGRUNTIMEINLINE int +SWIG_Python_CheckImplicit(swig_type_info *ty) +{ + PySwigClientData *data = (PySwigClientData *)ty->clientdata; + return data ? data->implicitconv : 0; +} + +SWIGRUNTIMEINLINE PyObject * +SWIG_Python_ExceptionType(swig_type_info *desc) { + PySwigClientData *data = desc ? (PySwigClientData *) desc->clientdata : 0; + PyObject *klass = data ? data->klass : 0; + return (klass ? klass : PyExc_RuntimeError); +} + + +SWIGRUNTIME PySwigClientData * +PySwigClientData_New(PyObject* obj) +{ + if (!obj) { + return 0; + } else { + PySwigClientData *data = (PySwigClientData *)malloc(sizeof(PySwigClientData)); + /* the klass element */ + data->klass = obj; + Py_INCREF(data->klass); + /* the newraw method and newargs arguments used to create a new raw instance */ + if (PyClass_Check(obj)) { + data->newraw = 0; + data->newargs = obj; + Py_INCREF(obj); + } else { +#if (PY_VERSION_HEX < 0x02020000) + data->newraw = 0; +#else + data->newraw = PyObject_GetAttrString(data->klass, (char *)"__new__"); +#endif + if (data->newraw) { + Py_INCREF(data->newraw); + data->newargs = PyTuple_New(1); + PyTuple_SetItem(data->newargs, 0, obj); + } else { + data->newargs = obj; + } + Py_INCREF(data->newargs); + } + /* the destroy method, aka as the C++ delete method */ + data->destroy = PyObject_GetAttrString(data->klass, (char *)"__swig_destroy__"); + if (PyErr_Occurred()) { + PyErr_Clear(); + data->destroy = 0; + } + if (data->destroy) { + int flags; + Py_INCREF(data->destroy); + flags = PyCFunction_GET_FLAGS(data->destroy); +#ifdef METH_O + data->delargs = !(flags & (METH_O)); +#else + data->delargs = 0; +#endif + } else { + data->delargs = 0; + } + data->implicitconv = 0; + return data; + } +} + +SWIGRUNTIME void +PySwigClientData_Del(PySwigClientData* data) +{ + Py_XDECREF(data->newraw); + Py_XDECREF(data->newargs); + Py_XDECREF(data->destroy); +} + +/* =============== PySwigObject =====================*/ + +typedef struct { + PyObject_HEAD + void *ptr; + swig_type_info *ty; + int own; + PyObject *next; +} PySwigObject; + +SWIGRUNTIME PyObject * +PySwigObject_long(PySwigObject *v) +{ + return PyLong_FromVoidPtr(v->ptr); +} + +SWIGRUNTIME PyObject * +PySwigObject_format(const char* fmt, PySwigObject *v) +{ + PyObject *res = NULL; + PyObject *args = PyTuple_New(1); + if (args) { + if (PyTuple_SetItem(args, 0, PySwigObject_long(v)) == 0) { + PyObject *ofmt = PyString_FromString(fmt); + if (ofmt) { + res = PyString_Format(ofmt,args); + Py_DECREF(ofmt); + } + Py_DECREF(args); + } + } + return res; +} + +SWIGRUNTIME PyObject * +PySwigObject_oct(PySwigObject *v) +{ + return PySwigObject_format("%o",v); +} + +SWIGRUNTIME PyObject * +PySwigObject_hex(PySwigObject *v) +{ + return PySwigObject_format("%x",v); +} + +SWIGRUNTIME PyObject * +#ifdef METH_NOARGS +PySwigObject_repr(PySwigObject *v) +#else +PySwigObject_repr(PySwigObject *v, PyObject *args) +#endif +{ + const char *name = SWIG_TypePrettyName(v->ty); + PyObject *hex = PySwigObject_hex(v); + PyObject *repr = PyString_FromFormat("<Swig Object of type '%s' at 0x%s>", name, PyString_AsString(hex)); + Py_DECREF(hex); + if (v->next) { +#ifdef METH_NOARGS + PyObject *nrep = PySwigObject_repr((PySwigObject *)v->next); +#else + PyObject *nrep = PySwigObject_repr((PySwigObject *)v->next, args); +#endif + PyString_ConcatAndDel(&repr,nrep); + } + return repr; +} + +SWIGRUNTIME int +PySwigObject_print(PySwigObject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) +{ +#ifdef METH_NOARGS + PyObject *repr = PySwigObject_repr(v); +#else + PyObject *repr = PySwigObject_repr(v, NULL); +#endif + if (repr) { + fputs(PyString_AsString(repr), fp); + Py_DECREF(repr); + return 0; + } else { + return 1; + } +} + +SWIGRUNTIME PyObject * +PySwigObject_str(PySwigObject *v) +{ + char result[SWIG_BUFFER_SIZE]; + return SWIG_PackVoidPtr(result, v->ptr, v->ty->name, sizeof(result)) ? + PyString_FromString(result) : 0; +} + +SWIGRUNTIME int +PySwigObject_compare(PySwigObject *v, PySwigObject *w) +{ + void *i = v->ptr; + void *j = w->ptr; + return (i < j) ? -1 : ((i > j) ? 1 : 0); +} + +SWIGRUNTIME PyTypeObject* _PySwigObject_type(void); + +SWIGRUNTIME PyTypeObject* +PySwigObject_type(void) { + static PyTypeObject *SWIG_STATIC_POINTER(type) = _PySwigObject_type(); + return type; +} + +SWIGRUNTIMEINLINE int +PySwigObject_Check(PyObject *op) { + return ((op)->ob_type == PySwigObject_type()) + || (strcmp((op)->ob_type->tp_name,"PySwigObject") == 0); +} + +SWIGRUNTIME PyObject * +PySwigObject_New(void *ptr, swig_type_info *ty, int own); + +SWIGRUNTIME void +PySwigObject_dealloc(PyObject *v) +{ + PySwigObject *sobj = (PySwigObject *) v; + PyObject *next = sobj->next; + if (sobj->own == SWIG_POINTER_OWN) { + swig_type_info *ty = sobj->ty; + PySwigClientData *data = ty ? (PySwigClientData *) ty->clientdata : 0; + PyObject *destroy = data ? data->destroy : 0; + if (destroy) { + /* destroy is always a VARARGS method */ + PyObject *res; + if (data->delargs) { + /* we need to create a temporal object to carry the destroy operation */ + PyObject *tmp = PySwigObject_New(sobj->ptr, ty, 0); + res = SWIG_Python_CallFunctor(destroy, tmp); + Py_DECREF(tmp); + } else { + PyCFunction meth = PyCFunction_GET_FUNCTION(destroy); + PyObject *mself = PyCFunction_GET_SELF(destroy); + res = ((*meth)(mself, v)); + } + Py_XDECREF(res); + } +#if !defined(SWIG_PYTHON_SILENT_MEMLEAK) + else { + const char *name = SWIG_TypePrettyName(ty); + printf("swig/python detected a memory leak of type '%s', no destructor found.\n", (name ? name : "unknown")); + } +#endif + } + Py_XDECREF(next); + PyObject_DEL(v); +} + +SWIGRUNTIME PyObject* +PySwigObject_append(PyObject* v, PyObject* next) +{ + PySwigObject *sobj = (PySwigObject *) v; +#ifndef METH_O + PyObject *tmp = 0; + if (!PyArg_ParseTuple(next,(char *)"O:append", &tmp)) return NULL; + next = tmp; +#endif + if (!PySwigObject_Check(next)) { + return NULL; + } + sobj->next = next; + Py_INCREF(next); + return SWIG_Py_Void(); +} + +SWIGRUNTIME PyObject* +#ifdef METH_NOARGS +PySwigObject_next(PyObject* v) +#else +PySwigObject_next(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + PySwigObject *sobj = (PySwigObject *) v; + if (sobj->next) { + Py_INCREF(sobj->next); + return sobj->next; + } else { + return SWIG_Py_Void(); + } +} + +SWIGINTERN PyObject* +#ifdef METH_NOARGS +PySwigObject_disown(PyObject *v) +#else +PySwigObject_disown(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + PySwigObject *sobj = (PySwigObject *)v; + sobj->own = 0; + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject* +#ifdef METH_NOARGS +PySwigObject_acquire(PyObject *v) +#else +PySwigObject_acquire(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + PySwigObject *sobj = (PySwigObject *)v; + sobj->own = SWIG_POINTER_OWN; + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject* +PySwigObject_own(PyObject *v, PyObject *args) +{ + PyObject *val = 0; +#if (PY_VERSION_HEX < 0x02020000) + if (!PyArg_ParseTuple(args,(char *)"|O:own",&val)) +#else + if (!PyArg_UnpackTuple(args, (char *)"own", 0, 1, &val)) +#endif + { + return NULL; + } + else + { + PySwigObject *sobj = (PySwigObject *)v; + PyObject *obj = PyBool_FromLong(sobj->own); + if (val) { +#ifdef METH_NOARGS + if (PyObject_IsTrue(val)) { + PySwigObject_acquire(v); + } else { + PySwigObject_disown(v); + } +#else + if (PyObject_IsTrue(val)) { + PySwigObject_acquire(v,args); + } else { + PySwigObject_disown(v,args); + } +#endif + } + return obj; + } +} + +#ifdef METH_O +static PyMethodDef +swigobject_methods[] = { + {(char *)"disown", (PyCFunction)PySwigObject_disown, METH_NOARGS, (char *)"releases ownership of the pointer"}, + {(char *)"acquire", (PyCFunction)PySwigObject_acquire, METH_NOARGS, (char *)"aquires ownership of the pointer"}, + {(char *)"own", (PyCFunction)PySwigObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"}, + {(char *)"append", (PyCFunction)PySwigObject_append, METH_O, (char *)"appends another 'this' object"}, + {(char *)"next", (PyCFunction)PySwigObject_next, METH_NOARGS, (char *)"returns the next 'this' object"}, + {(char *)"__repr__",(PyCFunction)PySwigObject_repr, METH_NOARGS, (char *)"returns object representation"}, + {0, 0, 0, 0} +}; +#else +static PyMethodDef +swigobject_methods[] = { + {(char *)"disown", (PyCFunction)PySwigObject_disown, METH_VARARGS, (char *)"releases ownership of the pointer"}, + {(char *)"acquire", (PyCFunction)PySwigObject_acquire, METH_VARARGS, (char *)"aquires ownership of the pointer"}, + {(char *)"own", (PyCFunction)PySwigObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"}, + {(char *)"append", (PyCFunction)PySwigObject_append, METH_VARARGS, (char *)"appends another 'this' object"}, + {(char *)"next", (PyCFunction)PySwigObject_next, METH_VARARGS, (char *)"returns the next 'this' object"}, + {(char *)"__repr__",(PyCFunction)PySwigObject_repr, METH_VARARGS, (char *)"returns object representation"}, + {0, 0, 0, 0} +}; +#endif + +#if PY_VERSION_HEX < 0x02020000 +SWIGINTERN PyObject * +PySwigObject_getattr(PySwigObject *sobj,char *name) +{ + return Py_FindMethod(swigobject_methods, (PyObject *)sobj, name); +} +#endif + +SWIGRUNTIME PyTypeObject* +_PySwigObject_type(void) { + static char swigobject_doc[] = "Swig object carries a C/C++ instance pointer"; + + static PyNumberMethods PySwigObject_as_number = { + (binaryfunc)0, /*nb_add*/ + (binaryfunc)0, /*nb_subtract*/ + (binaryfunc)0, /*nb_multiply*/ + (binaryfunc)0, /*nb_divide*/ + (binaryfunc)0, /*nb_remainder*/ + (binaryfunc)0, /*nb_divmod*/ + (ternaryfunc)0,/*nb_power*/ + (unaryfunc)0, /*nb_negative*/ + (unaryfunc)0, /*nb_positive*/ + (unaryfunc)0, /*nb_absolute*/ + (inquiry)0, /*nb_nonzero*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ + (coercion)0, /*nb_coerce*/ + (unaryfunc)PySwigObject_long, /*nb_int*/ + (unaryfunc)PySwigObject_long, /*nb_long*/ + (unaryfunc)0, /*nb_float*/ + (unaryfunc)PySwigObject_oct, /*nb_oct*/ + (unaryfunc)PySwigObject_hex, /*nb_hex*/ +#if PY_VERSION_HEX >= 0x02050000 /* 2.5.0 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index */ +#elif PY_VERSION_HEX >= 0x02020000 /* 2.2.0 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_true_divide */ +#elif PY_VERSION_HEX >= 0x02000000 /* 2.0.0 */ + 0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_or */ +#endif + }; + + static PyTypeObject pyswigobject_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp + = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + (char *)"PySwigObject", /* tp_name */ + sizeof(PySwigObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)PySwigObject_dealloc, /* tp_dealloc */ + (printfunc)PySwigObject_print, /* tp_print */ +#if PY_VERSION_HEX < 0x02020000 + (getattrfunc)PySwigObject_getattr, /* tp_getattr */ +#else + (getattrfunc)0, /* tp_getattr */ +#endif + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)PySwigObject_compare, /* tp_compare */ + (reprfunc)PySwigObject_repr, /* tp_repr */ + &PySwigObject_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)PySwigObject_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + swigobject_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0, /* tp_iter */ + 0, /* tp_iternext */ + swigobject_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + pyswigobject_type = tmp; + pyswigobject_type.ob_type = &PyType_Type; + type_init = 1; + } + return &pyswigobject_type; +} + +SWIGRUNTIME PyObject * +PySwigObject_New(void *ptr, swig_type_info *ty, int own) +{ + PySwigObject *sobj = PyObject_NEW(PySwigObject, PySwigObject_type()); + if (sobj) { + sobj->ptr = ptr; + sobj->ty = ty; + sobj->own = own; + sobj->next = 0; + } + return (PyObject *)sobj; +} + +/* ----------------------------------------------------------------------------- + * Implements a simple Swig Packed type, and use it instead of string + * ----------------------------------------------------------------------------- */ + +typedef struct { + PyObject_HEAD + void *pack; + swig_type_info *ty; + size_t size; +} PySwigPacked; + +SWIGRUNTIME int +PySwigPacked_print(PySwigPacked *v, FILE *fp, int SWIGUNUSEDPARM(flags)) +{ + char result[SWIG_BUFFER_SIZE]; + fputs("<Swig Packed ", fp); + if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) { + fputs("at ", fp); + fputs(result, fp); + } + fputs(v->ty->name,fp); + fputs(">", fp); + return 0; +} + +SWIGRUNTIME PyObject * +PySwigPacked_repr(PySwigPacked *v) +{ + char result[SWIG_BUFFER_SIZE]; + if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) { + return PyString_FromFormat("<Swig Packed at %s%s>", result, v->ty->name); + } else { + return PyString_FromFormat("<Swig Packed %s>", v->ty->name); + } +} + +SWIGRUNTIME PyObject * +PySwigPacked_str(PySwigPacked *v) +{ + char result[SWIG_BUFFER_SIZE]; + if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))){ + return PyString_FromFormat("%s%s", result, v->ty->name); + } else { + return PyString_FromString(v->ty->name); + } +} + +SWIGRUNTIME int +PySwigPacked_compare(PySwigPacked *v, PySwigPacked *w) +{ + size_t i = v->size; + size_t j = w->size; + int s = (i < j) ? -1 : ((i > j) ? 1 : 0); + return s ? s : strncmp((char *)v->pack, (char *)w->pack, 2*v->size); +} + +SWIGRUNTIME PyTypeObject* _PySwigPacked_type(void); + +SWIGRUNTIME PyTypeObject* +PySwigPacked_type(void) { + static PyTypeObject *SWIG_STATIC_POINTER(type) = _PySwigPacked_type(); + return type; +} + +SWIGRUNTIMEINLINE int +PySwigPacked_Check(PyObject *op) { + return ((op)->ob_type == _PySwigPacked_type()) + || (strcmp((op)->ob_type->tp_name,"PySwigPacked") == 0); +} + +SWIGRUNTIME void +PySwigPacked_dealloc(PyObject *v) +{ + if (PySwigPacked_Check(v)) { + PySwigPacked *sobj = (PySwigPacked *) v; + free(sobj->pack); + } + PyObject_DEL(v); +} + +SWIGRUNTIME PyTypeObject* +_PySwigPacked_type(void) { + static char swigpacked_doc[] = "Swig object carries a C/C++ instance pointer"; + static PyTypeObject pyswigpacked_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp + = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + (char *)"PySwigPacked", /* tp_name */ + sizeof(PySwigPacked), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)PySwigPacked_dealloc, /* tp_dealloc */ + (printfunc)PySwigPacked_print, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)PySwigPacked_compare, /* tp_compare */ + (reprfunc)PySwigPacked_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)PySwigPacked_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + swigpacked_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + pyswigpacked_type = tmp; + pyswigpacked_type.ob_type = &PyType_Type; + type_init = 1; + } + return &pyswigpacked_type; +} + +SWIGRUNTIME PyObject * +PySwigPacked_New(void *ptr, size_t size, swig_type_info *ty) +{ + PySwigPacked *sobj = PyObject_NEW(PySwigPacked, PySwigPacked_type()); + if (sobj) { + void *pack = malloc(size); + if (pack) { + memcpy(pack, ptr, size); + sobj->pack = pack; + sobj->ty = ty; + sobj->size = size; + } else { + PyObject_DEL((PyObject *) sobj); + sobj = 0; + } + } + return (PyObject *) sobj; +} + +SWIGRUNTIME swig_type_info * +PySwigPacked_UnpackData(PyObject *obj, void *ptr, size_t size) +{ + if (PySwigPacked_Check(obj)) { + PySwigPacked *sobj = (PySwigPacked *)obj; + if (sobj->size != size) return 0; + memcpy(ptr, sobj->pack, size); + return sobj->ty; + } else { + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * pointers/data manipulation + * ----------------------------------------------------------------------------- */ + +SWIGRUNTIMEINLINE PyObject * +_SWIG_This(void) +{ + return PyString_FromString("this"); +} + +SWIGRUNTIME PyObject * +SWIG_This(void) +{ + static PyObject *SWIG_STATIC_POINTER(swig_this) = _SWIG_This(); + return swig_this; +} + +/* #define SWIG_PYTHON_SLOW_GETSET_THIS */ + +SWIGRUNTIME PySwigObject * +SWIG_Python_GetSwigThis(PyObject *pyobj) +{ + if (PySwigObject_Check(pyobj)) { + return (PySwigObject *) pyobj; + } else { + PyObject *obj = 0; +#if (!defined(SWIG_PYTHON_SLOW_GETSET_THIS) && (PY_VERSION_HEX >= 0x02030000)) + if (PyInstance_Check(pyobj)) { + obj = _PyInstance_Lookup(pyobj, SWIG_This()); + } else { + PyObject **dictptr = _PyObject_GetDictPtr(pyobj); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + obj = dict ? PyDict_GetItem(dict, SWIG_This()) : 0; + } else { +#ifdef PyWeakref_CheckProxy + if (PyWeakref_CheckProxy(pyobj)) { + PyObject *wobj = PyWeakref_GET_OBJECT(pyobj); + return wobj ? SWIG_Python_GetSwigThis(wobj) : 0; + } +#endif + obj = PyObject_GetAttr(pyobj,SWIG_This()); + if (obj) { + Py_DECREF(obj); + } else { + if (PyErr_Occurred()) PyErr_Clear(); + return 0; + } + } + } +#else + obj = PyObject_GetAttr(pyobj,SWIG_This()); + if (obj) { + Py_DECREF(obj); + } else { + if (PyErr_Occurred()) PyErr_Clear(); + return 0; + } +#endif + if (obj && !PySwigObject_Check(obj)) { + /* a PyObject is called 'this', try to get the 'real this' + PySwigObject from it */ + return SWIG_Python_GetSwigThis(obj); + } + return (PySwigObject *)obj; + } +} + +/* Acquire a pointer value */ + +SWIGRUNTIME int +SWIG_Python_AcquirePtr(PyObject *obj, int own) { + if (own == SWIG_POINTER_OWN) { + PySwigObject *sobj = SWIG_Python_GetSwigThis(obj); + if (sobj) { + int oldown = sobj->own; + sobj->own = own; + return oldown; + } + } + return 0; +} + +/* Convert a pointer value */ + +SWIGRUNTIME int +SWIG_Python_ConvertPtrAndOwn(PyObject *obj, void **ptr, swig_type_info *ty, int flags, int *own) { + if (!obj) return SWIG_ERROR; + if (obj == Py_None) { + if (ptr) *ptr = 0; + return SWIG_OK; + } else { + PySwigObject *sobj = SWIG_Python_GetSwigThis(obj); + if (own) + *own = 0; + while (sobj) { + void *vptr = sobj->ptr; + if (ty) { + swig_type_info *to = sobj->ty; + if (to == ty) { + /* no type cast needed */ + if (ptr) *ptr = vptr; + break; + } else { + swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); + if (!tc) { + sobj = (PySwigObject *)sobj->next; + } else { + if (ptr) { + int newmemory = 0; + *ptr = SWIG_TypeCast(tc,vptr,&newmemory); + if (newmemory == SWIG_CAST_NEW_MEMORY) { + assert(own); + if (own) + *own = *own | SWIG_CAST_NEW_MEMORY; + } + } + break; + } + } + } else { + if (ptr) *ptr = vptr; + break; + } + } + if (sobj) { + if (own) + *own = *own | sobj->own; + if (flags & SWIG_POINTER_DISOWN) { + sobj->own = 0; + } + return SWIG_OK; + } else { + int res = SWIG_ERROR; + if (flags & SWIG_POINTER_IMPLICIT_CONV) { + PySwigClientData *data = ty ? (PySwigClientData *) ty->clientdata : 0; + if (data && !data->implicitconv) { + PyObject *klass = data->klass; + if (klass) { + PyObject *impconv; + data->implicitconv = 1; /* avoid recursion and call 'explicit' constructors*/ + impconv = SWIG_Python_CallFunctor(klass, obj); + data->implicitconv = 0; + if (PyErr_Occurred()) { + PyErr_Clear(); + impconv = 0; + } + if (impconv) { + PySwigObject *iobj = SWIG_Python_GetSwigThis(impconv); + if (iobj) { + void *vptr; + res = SWIG_Python_ConvertPtrAndOwn((PyObject*)iobj, &vptr, ty, 0, 0); + if (SWIG_IsOK(res)) { + if (ptr) { + *ptr = vptr; + /* transfer the ownership to 'ptr' */ + iobj->own = 0; + res = SWIG_AddCast(res); + res = SWIG_AddNewMask(res); + } else { + res = SWIG_AddCast(res); + } + } + } + Py_DECREF(impconv); + } + } + } + } + return res; + } + } +} + +/* Convert a function ptr value */ + +SWIGRUNTIME int +SWIG_Python_ConvertFunctionPtr(PyObject *obj, void **ptr, swig_type_info *ty) { + if (!PyCFunction_Check(obj)) { + return SWIG_ConvertPtr(obj, ptr, ty, 0); + } else { + void *vptr = 0; + + /* here we get the method pointer for callbacks */ + const char *doc = (((PyCFunctionObject *)obj) -> m_ml -> ml_doc); + const char *desc = doc ? strstr(doc, "swig_ptr: ") : 0; + if (desc) { + desc = ty ? SWIG_UnpackVoidPtr(desc + 10, &vptr, ty->name) : 0; + if (!desc) return SWIG_ERROR; + } + if (ty) { + swig_cast_info *tc = SWIG_TypeCheck(desc,ty); + if (tc) { + int newmemory = 0; + *ptr = SWIG_TypeCast(tc,vptr,&newmemory); + assert(!newmemory); /* newmemory handling not yet implemented */ + } else { + return SWIG_ERROR; + } + } else { + *ptr = vptr; + } + return SWIG_OK; + } +} + +/* Convert a packed value value */ + +SWIGRUNTIME int +SWIG_Python_ConvertPacked(PyObject *obj, void *ptr, size_t sz, swig_type_info *ty) { + swig_type_info *to = PySwigPacked_UnpackData(obj, ptr, sz); + if (!to) return SWIG_ERROR; + if (ty) { + if (to != ty) { + /* check type cast? */ + swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); + if (!tc) return SWIG_ERROR; + } + } + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Create a new pointer object + * ----------------------------------------------------------------------------- */ + +/* + Create a new instance object, whitout calling __init__, and set the + 'this' attribute. +*/ + +SWIGRUNTIME PyObject* +SWIG_Python_NewShadowInstance(PySwigClientData *data, PyObject *swig_this) +{ +#if (PY_VERSION_HEX >= 0x02020000) + PyObject *inst = 0; + PyObject *newraw = data->newraw; + if (newraw) { + inst = PyObject_Call(newraw, data->newargs, NULL); + if (inst) { +#if !defined(SWIG_PYTHON_SLOW_GETSET_THIS) + PyObject **dictptr = _PyObject_GetDictPtr(inst); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + if (dict == NULL) { + dict = PyDict_New(); + *dictptr = dict; + PyDict_SetItem(dict, SWIG_This(), swig_this); + } + } +#else + PyObject *key = SWIG_This(); + PyObject_SetAttr(inst, key, swig_this); +#endif + } + } else { + PyObject *dict = PyDict_New(); + PyDict_SetItem(dict, SWIG_This(), swig_this); + inst = PyInstance_NewRaw(data->newargs, dict); + Py_DECREF(dict); + } + return inst; +#else +#if (PY_VERSION_HEX >= 0x02010000) + PyObject *inst; + PyObject *dict = PyDict_New(); + PyDict_SetItem(dict, SWIG_This(), swig_this); + inst = PyInstance_NewRaw(data->newargs, dict); + Py_DECREF(dict); + return (PyObject *) inst; +#else + PyInstanceObject *inst = PyObject_NEW(PyInstanceObject, &PyInstance_Type); + if (inst == NULL) { + return NULL; + } + inst->in_class = (PyClassObject *)data->newargs; + Py_INCREF(inst->in_class); + inst->in_dict = PyDict_New(); + if (inst->in_dict == NULL) { + Py_DECREF(inst); + return NULL; + } +#ifdef Py_TPFLAGS_HAVE_WEAKREFS + inst->in_weakreflist = NULL; +#endif +#ifdef Py_TPFLAGS_GC + PyObject_GC_Init(inst); +#endif + PyDict_SetItem(inst->in_dict, SWIG_This(), swig_this); + return (PyObject *) inst; +#endif +#endif +} + +SWIGRUNTIME void +SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this) +{ + PyObject *dict; +#if (PY_VERSION_HEX >= 0x02020000) && !defined(SWIG_PYTHON_SLOW_GETSET_THIS) + PyObject **dictptr = _PyObject_GetDictPtr(inst); + if (dictptr != NULL) { + dict = *dictptr; + if (dict == NULL) { + dict = PyDict_New(); + *dictptr = dict; + } + PyDict_SetItem(dict, SWIG_This(), swig_this); + return; + } +#endif + dict = PyObject_GetAttrString(inst, (char*)"__dict__"); + PyDict_SetItem(dict, SWIG_This(), swig_this); + Py_DECREF(dict); +} + + +SWIGINTERN PyObject * +SWIG_Python_InitShadowInstance(PyObject *args) { + PyObject *obj[2]; + if (!SWIG_Python_UnpackTuple(args,(char*)"swiginit", 2, 2, obj)) { + return NULL; + } else { + PySwigObject *sthis = SWIG_Python_GetSwigThis(obj[0]); + if (sthis) { + PySwigObject_append((PyObject*) sthis, obj[1]); + } else { + SWIG_Python_SetSwigThis(obj[0], obj[1]); + } + return SWIG_Py_Void(); + } +} + +/* Create a new pointer object */ + +SWIGRUNTIME PyObject * +SWIG_Python_NewPointerObj(void *ptr, swig_type_info *type, int flags) { + if (!ptr) { + return SWIG_Py_Void(); + } else { + int own = (flags & SWIG_POINTER_OWN) ? SWIG_POINTER_OWN : 0; + PyObject *robj = PySwigObject_New(ptr, type, own); + PySwigClientData *clientdata = type ? (PySwigClientData *)(type->clientdata) : 0; + if (clientdata && !(flags & SWIG_POINTER_NOSHADOW)) { + PyObject *inst = SWIG_Python_NewShadowInstance(clientdata, robj); + if (inst) { + Py_DECREF(robj); + robj = inst; + } + } + return robj; + } +} + +/* Create a new packed object */ + +SWIGRUNTIMEINLINE PyObject * +SWIG_Python_NewPackedObj(void *ptr, size_t sz, swig_type_info *type) { + return ptr ? PySwigPacked_New((void *) ptr, sz, type) : SWIG_Py_Void(); +} + +/* -----------------------------------------------------------------------------* + * Get type list + * -----------------------------------------------------------------------------*/ + +#ifdef SWIG_LINK_RUNTIME +void *SWIG_ReturnGlobalTypeList(void *); +#endif + +SWIGRUNTIME swig_module_info * +SWIG_Python_GetModule(void) { + static void *type_pointer = (void *)0; + /* first check if module already created */ + if (!type_pointer) { +#ifdef SWIG_LINK_RUNTIME + type_pointer = SWIG_ReturnGlobalTypeList((void *)0); +#else + type_pointer = PyCObject_Import((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, + (char*)"type_pointer" SWIG_TYPE_TABLE_NAME); + if (PyErr_Occurred()) { + PyErr_Clear(); + type_pointer = (void *)0; + } +#endif + } + return (swig_module_info *) type_pointer; +} + +#if PY_MAJOR_VERSION < 2 +/* PyModule_AddObject function was introduced in Python 2.0. The following function + is copied out of Python/modsupport.c in python version 2.3.4 */ +SWIGINTERN int +PyModule_AddObject(PyObject *m, char *name, PyObject *o) +{ + PyObject *dict; + if (!PyModule_Check(m)) { + PyErr_SetString(PyExc_TypeError, + "PyModule_AddObject() needs module as first arg"); + return SWIG_ERROR; + } + if (!o) { + PyErr_SetString(PyExc_TypeError, + "PyModule_AddObject() needs non-NULL value"); + return SWIG_ERROR; + } + + dict = PyModule_GetDict(m); + if (dict == NULL) { + /* Internal error -- modules must have a dict! */ + PyErr_Format(PyExc_SystemError, "module '%s' has no __dict__", + PyModule_GetName(m)); + return SWIG_ERROR; + } + if (PyDict_SetItemString(dict, name, o)) + return SWIG_ERROR; + Py_DECREF(o); + return SWIG_OK; +} +#endif + +SWIGRUNTIME void +SWIG_Python_DestroyModule(void *vptr) +{ + swig_module_info *swig_module = (swig_module_info *) vptr; + swig_type_info **types = swig_module->types; + size_t i; + for (i =0; i < swig_module->size; ++i) { + swig_type_info *ty = types[i]; + if (ty->owndata) { + PySwigClientData *data = (PySwigClientData *) ty->clientdata; + if (data) PySwigClientData_Del(data); + } + } + Py_DECREF(SWIG_This()); +} + +SWIGRUNTIME void +SWIG_Python_SetModule(swig_module_info *swig_module) { + static PyMethodDef swig_empty_runtime_method_table[] = { {NULL, NULL, 0, NULL} };/* Sentinel */ + + PyObject *module = Py_InitModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, + swig_empty_runtime_method_table); + PyObject *pointer = PyCObject_FromVoidPtr((void *) swig_module, SWIG_Python_DestroyModule); + if (pointer && module) { + PyModule_AddObject(module, (char*)"type_pointer" SWIG_TYPE_TABLE_NAME, pointer); + } else { + Py_XDECREF(pointer); + } +} + +/* The python cached type query */ +SWIGRUNTIME PyObject * +SWIG_Python_TypeCache(void) { + static PyObject *SWIG_STATIC_POINTER(cache) = PyDict_New(); + return cache; +} + +SWIGRUNTIME swig_type_info * +SWIG_Python_TypeQuery(const char *type) +{ + PyObject *cache = SWIG_Python_TypeCache(); + PyObject *key = PyString_FromString(type); + PyObject *obj = PyDict_GetItem(cache, key); + swig_type_info *descriptor; + if (obj) { + descriptor = (swig_type_info *) PyCObject_AsVoidPtr(obj); + } else { + swig_module_info *swig_module = SWIG_Python_GetModule(); + descriptor = SWIG_TypeQueryModule(swig_module, swig_module, type); + if (descriptor) { + obj = PyCObject_FromVoidPtr(descriptor, NULL); + PyDict_SetItem(cache, key, obj); + Py_DECREF(obj); + } + } + Py_DECREF(key); + return descriptor; +} + +/* + For backward compatibility only +*/ +#define SWIG_POINTER_EXCEPTION 0 +#define SWIG_arg_fail(arg) SWIG_Python_ArgFail(arg) +#define SWIG_MustGetPtr(p, type, argnum, flags) SWIG_Python_MustGetPtr(p, type, argnum, flags) + +SWIGRUNTIME int +SWIG_Python_AddErrMesg(const char* mesg, int infront) +{ + if (PyErr_Occurred()) { + PyObject *type = 0; + PyObject *value = 0; + PyObject *traceback = 0; + PyErr_Fetch(&type, &value, &traceback); + if (value) { + PyObject *old_str = PyObject_Str(value); + Py_XINCREF(type); + PyErr_Clear(); + if (infront) { + PyErr_Format(type, "%s %s", mesg, PyString_AsString(old_str)); + } else { + PyErr_Format(type, "%s %s", PyString_AsString(old_str), mesg); + } + Py_DECREF(old_str); + } + return 1; + } else { + return 0; + } +} + +SWIGRUNTIME int +SWIG_Python_ArgFail(int argnum) +{ + if (PyErr_Occurred()) { + /* add information about failing argument */ + char mesg[256]; + PyOS_snprintf(mesg, sizeof(mesg), "argument number %d:", argnum); + return SWIG_Python_AddErrMesg(mesg, 1); + } else { + return 0; + } +} + +SWIGRUNTIMEINLINE const char * +PySwigObject_GetDesc(PyObject *self) +{ + PySwigObject *v = (PySwigObject *)self; + swig_type_info *ty = v ? v->ty : 0; + return ty ? ty->str : (char*)""; +} + +SWIGRUNTIME void +SWIG_Python_TypeError(const char *type, PyObject *obj) +{ + if (type) { +#if defined(SWIG_COBJECT_TYPES) + if (obj && PySwigObject_Check(obj)) { + const char *otype = (const char *) PySwigObject_GetDesc(obj); + if (otype) { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, 'PySwigObject(%s)' is received", + type, otype); + return; + } + } else +#endif + { + const char *otype = (obj ? obj->ob_type->tp_name : 0); + if (otype) { + PyObject *str = PyObject_Str(obj); + const char *cstr = str ? PyString_AsString(str) : 0; + if (cstr) { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s(%s)' is received", + type, otype, cstr); + } else { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s' is received", + type, otype); + } + Py_XDECREF(str); + return; + } + } + PyErr_Format(PyExc_TypeError, "a '%s' is expected", type); + } else { + PyErr_Format(PyExc_TypeError, "unexpected type is received"); + } +} + + +/* Convert a pointer value, signal an exception on a type mismatch */ +SWIGRUNTIME void * +SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int argnum, int flags) { + void *result; + if (SWIG_Python_ConvertPtr(obj, &result, ty, flags) == -1) { + PyErr_Clear(); + if (flags & SWIG_POINTER_EXCEPTION) { + SWIG_Python_TypeError(SWIG_TypePrettyName(ty), obj); + SWIG_Python_ArgFail(argnum); + } + } + return result; +} + + +#ifdef __cplusplus +#if 0 +{ /* cc-mode */ +#endif +} +#endif + + + +#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) + +#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else + + + + #define SWIG_exception(code, msg) do { SWIG_Error(code, msg); SWIG_fail;; } while(0) + + +/* -------- TYPES TABLE (BEGIN) -------- */ + +#define SWIGTYPE_p_TALLOC_CTX swig_types[0] +#define SWIGTYPE_p_auth_session_info swig_types[1] +#define SWIGTYPE_p_char swig_types[2] +#define SWIGTYPE_p_cli_credentials swig_types[3] +#define SWIGTYPE_p_dom_sid swig_types[4] +#define SWIGTYPE_p_int swig_types[5] +#define SWIGTYPE_p_ldb_context swig_types[6] +#define SWIGTYPE_p_ldb_dn swig_types[7] +#define SWIGTYPE_p_ldb_ldif swig_types[8] +#define SWIGTYPE_p_ldb_message swig_types[9] +#define SWIGTYPE_p_ldb_message_element swig_types[10] +#define SWIGTYPE_p_ldb_result swig_types[11] +#define SWIGTYPE_p_loadparm_context swig_types[12] +#define SWIGTYPE_p_loadparm_service swig_types[13] +#define SWIGTYPE_p_long_long swig_types[14] +#define SWIGTYPE_p_param_context swig_types[15] +#define SWIGTYPE_p_param_opt swig_types[16] +#define SWIGTYPE_p_param_section swig_types[17] +#define SWIGTYPE_p_security_descriptor swig_types[18] +#define SWIGTYPE_p_security_token swig_types[19] +#define SWIGTYPE_p_short swig_types[20] +#define SWIGTYPE_p_signed_char swig_types[21] +#define SWIGTYPE_p_unsigned_char swig_types[22] +#define SWIGTYPE_p_unsigned_int swig_types[23] +#define SWIGTYPE_p_unsigned_long swig_types[24] +#define SWIGTYPE_p_unsigned_long_long swig_types[25] +#define SWIGTYPE_p_unsigned_short swig_types[26] +static swig_type_info *swig_types[28]; +static swig_module_info swig_module = {swig_types, 27, 0, 0, 0, 0}; +#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name) +#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name) + +/* -------- TYPES TABLE (END) -------- */ + +#if (PY_VERSION_HEX <= 0x02000000) +# if !defined(SWIG_PYTHON_CLASSIC) +# error "This python version requires swig to be run with the '-classic' option" +# endif +#endif +#if (PY_VERSION_HEX <= 0x02020000) +# error "This python version requires swig to be run with the '-nomodern' option" +#endif +#if (PY_VERSION_HEX <= 0x02020000) +# error "This python version requires swig to be run with the '-nomodernargs' option" +#endif +#ifndef METH_O +# error "This python version requires swig to be run with the '-nofastunpack' option" +#endif +#ifdef SWIG_TypeQuery +# undef SWIG_TypeQuery +#endif +#define SWIG_TypeQuery SWIG_Python_TypeQuery + +/*----------------------------------------------- + @(target):= _misc.so + ------------------------------------------------*/ +#define SWIG_init init_misc + +#define SWIG_name "_misc" + +#define SWIGVERSION 0x010336 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#include "includes.h" +#include "ldb.h" +#include "param/param.h" +#include "auth/credentials/credentials.h" +#include "dsdb/samdb/samdb.h" +#include "lib/ldb-samba/ldif_handlers.h" +#include "librpc/ndr/libndr.h" +#include "version.h" + + +#include "libcli/util/pyerrors.h" + + +SWIGINTERN int +SWIG_AsVal_double (PyObject *obj, double *val) +{ + int res = SWIG_TypeError; + if (PyFloat_Check(obj)) { + if (val) *val = PyFloat_AsDouble(obj); + return SWIG_OK; + } else if (PyInt_Check(obj)) { + if (val) *val = PyInt_AsLong(obj); + return SWIG_OK; + } else if (PyLong_Check(obj)) { + double v = PyLong_AsDouble(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } +#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + double d = PyFloat_AsDouble(obj); + if (!PyErr_Occurred()) { + if (val) *val = d; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + long v = PyLong_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_AddCast(SWIG_OK)); + } else { + PyErr_Clear(); + } + } + } +#endif + return res; +} + + +#include <float.h> + + +#include <math.h> + + +SWIGINTERNINLINE int +SWIG_CanCastAsInteger(double *d, double min, double max) { + double x = *d; + if ((min <= x && x <= max)) { + double fx = floor(x); + double cx = ceil(x); + double rd = ((x - fx) < 0.5) ? fx : cx; /* simple rint */ + if ((errno == EDOM) || (errno == ERANGE)) { + errno = 0; + } else { + double summ, reps, diff; + if (rd < x) { + diff = x - rd; + } else if (rd > x) { + diff = rd - x; + } else { + return 1; + } + summ = rd + x; + reps = diff/summ; + if (reps < 8*DBL_EPSILON) { + *d = rd; + return 1; + } + } + } + return 0; +} + + +SWIGINTERN int +SWIG_AsVal_unsigned_SS_long (PyObject *obj, unsigned long *val) +{ + if (PyInt_Check(obj)) { + long v = PyInt_AsLong(obj); + if (v >= 0) { + if (val) *val = v; + return SWIG_OK; + } else { + return SWIG_OverflowError; + } + } else if (PyLong_Check(obj)) { + unsigned long v = PyLong_AsUnsignedLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } +#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + unsigned long v = PyLong_AsUnsignedLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + double d; + int res = SWIG_AddCast(SWIG_AsVal_double (obj,&d)); + if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, 0, ULONG_MAX)) { + if (val) *val = (unsigned long)(d); + return res; + } + } + } +#endif + return SWIG_TypeError; +} + + +SWIGINTERNINLINE int +SWIG_AsVal_size_t (PyObject * obj, size_t *val) +{ + unsigned long v; + int res = SWIG_AsVal_unsigned_SS_long (obj, val ? &v : 0); + if (SWIG_IsOK(res) && val) *val = (size_t)(v); + return res; +} + + +SWIGINTERN swig_type_info* +SWIG_pchar_descriptor(void) +{ + static int init = 0; + static swig_type_info* info = 0; + if (!init) { + info = SWIG_TypeQuery("_p_char"); + init = 1; + } + return info; +} + + +SWIGINTERNINLINE PyObject * +SWIG_FromCharPtrAndSize(const char* carray, size_t size) +{ + if (carray) { + if (size > INT_MAX) { + swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); + return pchar_descriptor ? + SWIG_NewPointerObj((char *)(carray), pchar_descriptor, 0) : SWIG_Py_Void(); + } else { + return PyString_FromStringAndSize(carray, (int)(size)); + } + } else { + return SWIG_Py_Void(); + } +} + + +SWIGINTERNINLINE PyObject * +SWIG_FromCharPtr(const char *cptr) +{ + return SWIG_FromCharPtrAndSize(cptr, (cptr ? strlen(cptr) : 0)); +} + + +void ldb_set_credentials(struct ldb_context *ldb, struct cli_credentials *creds) +{ + ldb_set_opaque(ldb, "credentials", creds); +} + +void ldb_set_session_info(struct ldb_context *ldb, struct auth_session_info *session_info) +{ + ldb_set_opaque(ldb, "sessionInfo", session_info); +} + +void ldb_set_loadparm(struct ldb_context *ldb, struct loadparm_context *lp_ctx) +{ + ldb_set_opaque(ldb, "loadparm", lp_ctx); +} + + + +SWIGINTERNINLINE PyObject* + SWIG_From_bool (bool value) +{ + return PyBool_FromLong(value ? 1 : 0); +} + + +SWIGINTERN int +SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc) +{ + if (PyString_Check(obj)) { + char *cstr; Py_ssize_t len; + PyString_AsStringAndSize(obj, &cstr, &len); + if (cptr) { + if (alloc) { + /* + In python the user should not be able to modify the inner + string representation. To warranty that, if you define + SWIG_PYTHON_SAFE_CSTRINGS, a new/copy of the python string + buffer is always returned. + + The default behavior is just to return the pointer value, + so, be careful. + */ +#if defined(SWIG_PYTHON_SAFE_CSTRINGS) + if (*alloc != SWIG_OLDOBJ) +#else + if (*alloc == SWIG_NEWOBJ) +#endif + { + *cptr = (char *)memcpy((char *)malloc((len + 1)*sizeof(char)), cstr, sizeof(char)*(len + 1)); + *alloc = SWIG_NEWOBJ; + } + else { + *cptr = cstr; + *alloc = SWIG_OLDOBJ; + } + } else { + *cptr = PyString_AsString(obj); + } + } + if (psize) *psize = len + 1; + return SWIG_OK; + } else { + swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); + if (pchar_descriptor) { + void* vptr = 0; + if (SWIG_ConvertPtr(obj, &vptr, pchar_descriptor, 0) == SWIG_OK) { + if (cptr) *cptr = (char *) vptr; + if (psize) *psize = vptr ? (strlen((char *)vptr) + 1) : 0; + if (alloc) *alloc = SWIG_OLDOBJ; + return SWIG_OK; + } + } + } + return SWIG_TypeError; +} + + + + + +const char *version(void) +{ + return SAMBA_VERSION_STRING; +} + + + #define SWIG_From_long PyInt_FromLong + + +SWIGINTERNINLINE PyObject * +SWIG_From_int (int value) +{ + return SWIG_From_long (value); +} + + +bool dsdb_set_ntds_invocation_id(struct ldb_context *ldb, const char *guid) +{ + struct GUID invocation_id_in; + if (NT_STATUS_IS_ERR(GUID_from_string(guid, &invocation_id_in))) { + return false; + } + return samdb_set_ntds_invocation_id(ldb, &invocation_id_in); +} + + +uint64_t unix2nttime(time_t t) +{ + NTTIME nt; + unix_to_nt_time(&nt, t); + return (uint64_t)nt; +} + + +#include <limits.h> +#if !defined(SWIG_NO_LLONG_MAX) +# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__) +# define LLONG_MAX __LONG_LONG_MAX__ +# define LLONG_MIN (-LLONG_MAX - 1LL) +# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) +# endif +#endif + + +SWIGINTERNINLINE PyObject* +SWIG_From_long_SS_long (long long value) +{ + return ((value < LONG_MIN) || (value > LONG_MAX)) ? + PyLong_FromLongLong(value) : PyInt_FromLong((long)(value)); +} + + +SWIGINTERNINLINE PyObject* +SWIG_From_unsigned_SS_long_SS_long (unsigned long long value) +{ + return (value > LONG_MAX) ? + PyLong_FromUnsignedLongLong(value) : PyInt_FromLong((long)(value)); +} + +#ifdef __cplusplus +extern "C" { +#endif +SWIGINTERN PyObject *_wrap_random_password(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + TALLOC_CTX *arg1 = (TALLOC_CTX *) 0 ; + size_t arg2 ; + size_t val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *) "len", NULL + }; + char *result = 0 ; + + arg1 = NULL; + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:random_password",kwnames,&obj0)) SWIG_fail; + ecode2 = SWIG_AsVal_size_t(obj0, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "random_password" "', argument " "2"" of type '" "size_t""'"); + } + arg2 = (size_t)(val2); + result = (char *)generate_random_str(arg1,arg2); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ldb_set_credentials(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + struct ldb_context *arg1 = (struct ldb_context *) 0 ; + struct cli_credentials *arg2 = (struct cli_credentials *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "ldb",(char *) "creds", NULL + }; + + arg2 = NULL; + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:ldb_set_credentials",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ldb_set_credentials" "', argument " "1"" of type '" "struct ldb_context *""'"); + } + arg1 = (struct ldb_context *)(argp1); + if (obj1) { + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_cli_credentials, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ldb_set_credentials" "', argument " "2"" of type '" "struct cli_credentials *""'"); + } + arg2 = (struct cli_credentials *)(argp2); + } + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + ldb_set_credentials(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ldb_set_session_info(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + struct ldb_context *arg1 = (struct ldb_context *) 0 ; + struct auth_session_info *arg2 = (struct auth_session_info *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "ldb",(char *) "session_info", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:ldb_set_session_info",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ldb_set_session_info" "', argument " "1"" of type '" "struct ldb_context *""'"); + } + arg1 = (struct ldb_context *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_auth_session_info, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ldb_set_session_info" "', argument " "2"" of type '" "struct auth_session_info *""'"); + } + arg2 = (struct auth_session_info *)(argp2); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + ldb_set_session_info(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ldb_set_loadparm(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + struct ldb_context *arg1 = (struct ldb_context *) 0 ; + struct loadparm_context *arg2 = (struct loadparm_context *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "ldb",(char *) "lp_ctx", NULL + }; + + arg2 = loadparm_init(NULL); + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:ldb_set_loadparm",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ldb_set_loadparm" "', argument " "1"" of type '" "struct ldb_context *""'"); + } + arg1 = (struct ldb_context *)(argp1); + if (obj1) { + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_loadparm_context, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ldb_set_loadparm" "', argument " "2"" of type '" "struct loadparm_context *""'"); + } + arg2 = (struct loadparm_context *)(argp2); + } + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + ldb_set_loadparm(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_samdb_set_domain_sid(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + struct ldb_context *arg1 = (struct ldb_context *) 0 ; + struct dom_sid *arg2 = (struct dom_sid *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "ldb",(char *) "dom_sid_in", NULL + }; + bool result; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:samdb_set_domain_sid",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "samdb_set_domain_sid" "', argument " "1"" of type '" "struct ldb_context *""'"); + } + arg1 = (struct ldb_context *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_dom_sid, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "samdb_set_domain_sid" "', argument " "2"" of type '" "struct dom_sid const *""'"); + } + arg2 = (struct dom_sid *)(argp2); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = (bool)samdb_set_domain_sid(arg1,(struct dom_sid const *)arg2); + resultobj = SWIG_From_bool((bool)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsdb_attach_schema_from_ldif_file(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + struct ldb_context *arg1 = (struct ldb_context *) 0 ; + char *arg2 = (char *) 0 ; + char *arg3 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + int res3 ; + char *buf3 = 0 ; + int alloc3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + char * kwnames[] = { + (char *) "ldb",(char *) "pf",(char *) "df", NULL + }; + WERROR result; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO:dsdb_attach_schema_from_ldif_file",kwnames,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsdb_attach_schema_from_ldif_file" "', argument " "1"" of type '" "struct ldb_context *""'"); + } + arg1 = (struct ldb_context *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dsdb_attach_schema_from_ldif_file" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "dsdb_attach_schema_from_ldif_file" "', argument " "3"" of type '" "char const *""'"); + } + arg3 = (char *)(buf3); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = dsdb_attach_schema_from_ldif_file(arg1,(char const *)arg2,(char const *)arg3); + if (!W_ERROR_IS_OK(result)) { + PyErr_SetWERROR(result); + SWIG_fail; + } else if (resultobj == NULL) { + resultobj = Py_None; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_version(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + char *result = 0 ; + + if (!SWIG_Python_UnpackTuple(args,"version",0,0,0)) SWIG_fail; + result = (char *)version(); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsdb_set_global_schema(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + struct ldb_context *arg1 = (struct ldb_context *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *) "ldb", NULL + }; + int result; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:dsdb_set_global_schema",kwnames,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsdb_set_global_schema" "', argument " "1"" of type '" "struct ldb_context *""'"); + } + arg1 = (struct ldb_context *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = (int)dsdb_set_global_schema(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ldb_register_samba_handlers(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + struct ldb_context *arg1 = (struct ldb_context *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *) "ldb", NULL + }; + int result; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:ldb_register_samba_handlers",kwnames,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ldb_register_samba_handlers" "', argument " "1"" of type '" "struct ldb_context *""'"); + } + arg1 = (struct ldb_context *)(argp1); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = (int)ldb_register_samba_handlers(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsdb_set_ntds_invocation_id(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + struct ldb_context *arg1 = (struct ldb_context *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "ldb",(char *) "guid", NULL + }; + bool result; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:dsdb_set_ntds_invocation_id",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsdb_set_ntds_invocation_id" "', argument " "1"" of type '" "struct ldb_context *""'"); + } + arg1 = (struct ldb_context *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dsdb_set_ntds_invocation_id" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + result = (bool)dsdb_set_ntds_invocation_id(arg1,(char const *)arg2); + resultobj = SWIG_From_bool((bool)(result)); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_private_path(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + TALLOC_CTX *arg1 = (TALLOC_CTX *) 0 ; + struct loadparm_context *arg2 = (struct loadparm_context *) 0 ; + char *arg3 = (char *) 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + int res3 ; + char *buf3 = 0 ; + int alloc3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "lp_ctx",(char *) "name", NULL + }; + char *result = 0 ; + + arg2 = loadparm_init(NULL); + arg1 = NULL; + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"|OO:private_path",kwnames,&obj0,&obj1)) SWIG_fail; + if (obj0) { + res2 = SWIG_ConvertPtr(obj0, &argp2,SWIGTYPE_p_loadparm_context, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "private_path" "', argument " "2"" of type '" "struct loadparm_context *""'"); + } + arg2 = (struct loadparm_context *)(argp2); + } + if (obj1) { + res3 = SWIG_AsCharPtrAndSize(obj1, &buf3, NULL, &alloc3); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "private_path" "', argument " "3"" of type '" "char const *""'"); + } + arg3 = (char *)(buf3); + } + result = (char *)private_path(arg1,arg2,(char const *)arg3); + resultobj = SWIG_FromCharPtr((const char *)result); + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return resultobj; +fail: + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_unix2nttime(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + time_t arg1 ; + unsigned long val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *) "t", NULL + }; + uint64_t result; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:unix2nttime",kwnames,&obj0)) SWIG_fail; + ecode1 = SWIG_AsVal_unsigned_SS_long(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "unix2nttime" "', argument " "1"" of type '" "time_t""'"); + } + arg1 = (time_t)(val1); + result = (uint64_t)unix2nttime(arg1); + resultobj = SWIG_From_unsigned_SS_long_SS_long((unsigned long long)(result)); + return resultobj; +fail: + return NULL; +} + + +static PyMethodDef SwigMethods[] = { + { (char *)"random_password", (PyCFunction) _wrap_random_password, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.random_password(len) -> string\n" + "Generate random password with specified length.\n" + ""}, + { (char *)"ldb_set_credentials", (PyCFunction) _wrap_ldb_set_credentials, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.set_credentials(credentials)\n" + "Set credentials to use when connecting.\n" + ""}, + { (char *)"ldb_set_session_info", (PyCFunction) _wrap_ldb_set_session_info, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.set_session_info(session_info)\n" + "Set session info to use when connecting.\n" + ""}, + { (char *)"ldb_set_loadparm", (PyCFunction) _wrap_ldb_set_loadparm, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.set_loadparm(session_info)\n" + "Set loadparm context to use when connecting.\n" + ""}, + { (char *)"samdb_set_domain_sid", (PyCFunction) _wrap_samdb_set_domain_sid, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.set_domain_sid(sid)\n" + "Set SID of domain to use.\n" + ""}, + { (char *)"dsdb_attach_schema_from_ldif_file", (PyCFunction) _wrap_dsdb_attach_schema_from_ldif_file, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"version", (PyCFunction)_wrap_version, METH_NOARGS, (char *)"\n" + "version()\n" + "Obtain the Samba version.\n" + ""}, + { (char *)"dsdb_set_global_schema", (PyCFunction) _wrap_dsdb_set_global_schema, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"ldb_register_samba_handlers", (PyCFunction) _wrap_ldb_register_samba_handlers, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "register_samba_handlers()\n" + "Register Samba-specific LDB modules and schemas.\n" + ""}, + { (char *)"dsdb_set_ntds_invocation_id", (PyCFunction) _wrap_dsdb_set_ntds_invocation_id, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"private_path", (PyCFunction) _wrap_private_path, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"unix2nttime", (PyCFunction) _wrap_unix2nttime, METH_VARARGS | METH_KEYWORDS, NULL}, + { NULL, NULL, 0, NULL } +}; + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */ + +static swig_type_info _swigt__p_TALLOC_CTX = {"_p_TALLOC_CTX", "TALLOC_CTX *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_auth_session_info = {"_p_auth_session_info", "struct auth_session_info *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_cli_credentials = {"_p_cli_credentials", "struct cli_credentials *|cli_credentials *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_dom_sid = {"_p_dom_sid", "struct dom_sid *|dom_sid *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_int = {"_p_int", "intptr_t *|int *|int_least32_t *|int_fast32_t *|int32_t *|int_fast16_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_context = {"_p_ldb_context", "struct ldb_context *|ldb *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_dn = {"_p_ldb_dn", "struct ldb_dn *|ldb_dn *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_ldif = {"_p_ldb_ldif", "struct ldb_ldif *|ldb_ldif *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_message = {"_p_ldb_message", "ldb_msg *|struct ldb_message *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_message_element = {"_p_ldb_message_element", "struct ldb_message_element *|ldb_message_element *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_result = {"_p_ldb_result", "struct ldb_result *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_loadparm_context = {"_p_loadparm_context", "struct loadparm_context *|loadparm_context *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_loadparm_service = {"_p_loadparm_service", "struct loadparm_service *|loadparm_service *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_long_long = {"_p_long_long", "int_least64_t *|int_fast64_t *|int64_t *|long long *|intmax_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_param_context = {"_p_param_context", "struct param_context *|param *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_param_opt = {"_p_param_opt", "struct param_opt *|param_opt *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_param_section = {"_p_param_section", "struct param_section *|param_section *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_security_descriptor = {"_p_security_descriptor", "struct security_descriptor *|security_descriptor *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_security_token = {"_p_security_token", "struct security_token *|security_token *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_short = {"_p_short", "short *|int_least16_t *|int16_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_signed_char = {"_p_signed_char", "signed char *|int_least8_t *|int_fast8_t *|int8_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_char = {"_p_unsigned_char", "unsigned char *|uint_least8_t *|uint_fast8_t *|uint8_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_int = {"_p_unsigned_int", "uintptr_t *|uint_least32_t *|uint_fast32_t *|uint32_t *|unsigned int *|uint_fast16_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_long = {"_p_unsigned_long", "unsigned long *|time_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_long_long = {"_p_unsigned_long_long", "uint_least64_t *|uint_fast64_t *|uint64_t *|unsigned long long *|uintmax_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_short = {"_p_unsigned_short", "unsigned short *|uint_least16_t *|uint16_t *", 0, 0, (void*)0, 0}; + +static swig_type_info *swig_type_initial[] = { + &_swigt__p_TALLOC_CTX, + &_swigt__p_auth_session_info, + &_swigt__p_char, + &_swigt__p_cli_credentials, + &_swigt__p_dom_sid, + &_swigt__p_int, + &_swigt__p_ldb_context, + &_swigt__p_ldb_dn, + &_swigt__p_ldb_ldif, + &_swigt__p_ldb_message, + &_swigt__p_ldb_message_element, + &_swigt__p_ldb_result, + &_swigt__p_loadparm_context, + &_swigt__p_loadparm_service, + &_swigt__p_long_long, + &_swigt__p_param_context, + &_swigt__p_param_opt, + &_swigt__p_param_section, + &_swigt__p_security_descriptor, + &_swigt__p_security_token, + &_swigt__p_short, + &_swigt__p_signed_char, + &_swigt__p_unsigned_char, + &_swigt__p_unsigned_int, + &_swigt__p_unsigned_long, + &_swigt__p_unsigned_long_long, + &_swigt__p_unsigned_short, +}; + +static swig_cast_info _swigc__p_TALLOC_CTX[] = { {&_swigt__p_TALLOC_CTX, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_auth_session_info[] = { {&_swigt__p_auth_session_info, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_char[] = { {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_cli_credentials[] = { {&_swigt__p_cli_credentials, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_dom_sid[] = { {&_swigt__p_dom_sid, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_int[] = { {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_context[] = { {&_swigt__p_ldb_context, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_dn[] = { {&_swigt__p_ldb_dn, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_ldif[] = { {&_swigt__p_ldb_ldif, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_message[] = { {&_swigt__p_ldb_message, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_message_element[] = { {&_swigt__p_ldb_message_element, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_result[] = { {&_swigt__p_ldb_result, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_loadparm_context[] = { {&_swigt__p_loadparm_context, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_loadparm_service[] = { {&_swigt__p_loadparm_service, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_long_long[] = { {&_swigt__p_long_long, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_param_context[] = { {&_swigt__p_param_context, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_param_opt[] = { {&_swigt__p_param_opt, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_param_section[] = { {&_swigt__p_param_section, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_security_descriptor[] = { {&_swigt__p_security_descriptor, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_security_token[] = { {&_swigt__p_security_token, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_short[] = { {&_swigt__p_short, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_signed_char[] = { {&_swigt__p_signed_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_char[] = { {&_swigt__p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_int[] = { {&_swigt__p_unsigned_int, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_long[] = { {&_swigt__p_unsigned_long, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_long_long[] = { {&_swigt__p_unsigned_long_long, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_short[] = { {&_swigt__p_unsigned_short, 0, 0, 0},{0, 0, 0, 0}}; + +static swig_cast_info *swig_cast_initial[] = { + _swigc__p_TALLOC_CTX, + _swigc__p_auth_session_info, + _swigc__p_char, + _swigc__p_cli_credentials, + _swigc__p_dom_sid, + _swigc__p_int, + _swigc__p_ldb_context, + _swigc__p_ldb_dn, + _swigc__p_ldb_ldif, + _swigc__p_ldb_message, + _swigc__p_ldb_message_element, + _swigc__p_ldb_result, + _swigc__p_loadparm_context, + _swigc__p_loadparm_service, + _swigc__p_long_long, + _swigc__p_param_context, + _swigc__p_param_opt, + _swigc__p_param_section, + _swigc__p_security_descriptor, + _swigc__p_security_token, + _swigc__p_short, + _swigc__p_signed_char, + _swigc__p_unsigned_char, + _swigc__p_unsigned_int, + _swigc__p_unsigned_long, + _swigc__p_unsigned_long_long, + _swigc__p_unsigned_short, +}; + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */ + +static swig_const_info swig_const_table[] = { +{0, 0, 0, 0.0, 0, 0}}; + +#ifdef __cplusplus +} +#endif +/* ----------------------------------------------------------------------------- + * Type initialization: + * This problem is tough by the requirement that no dynamic + * memory is used. Also, since swig_type_info structures store pointers to + * swig_cast_info structures and swig_cast_info structures store pointers back + * to swig_type_info structures, we need some lookup code at initialization. + * The idea is that swig generates all the structures that are needed. + * The runtime then collects these partially filled structures. + * The SWIG_InitializeModule function takes these initial arrays out of + * swig_module, and does all the lookup, filling in the swig_module.types + * array with the correct data and linking the correct swig_cast_info + * structures together. + * + * The generated swig_type_info structures are assigned staticly to an initial + * array. We just loop through that array, and handle each type individually. + * First we lookup if this type has been already loaded, and if so, use the + * loaded structure instead of the generated one. Then we have to fill in the + * cast linked list. The cast data is initially stored in something like a + * two-dimensional array. Each row corresponds to a type (there are the same + * number of rows as there are in the swig_type_initial array). Each entry in + * a column is one of the swig_cast_info structures for that type. + * The cast_initial array is actually an array of arrays, because each row has + * a variable number of columns. So to actually build the cast linked list, + * we find the array of casts associated with the type, and loop through it + * adding the casts to the list. The one last trick we need to do is making + * sure the type pointer in the swig_cast_info struct is correct. + * + * First off, we lookup the cast->type name to see if it is already loaded. + * There are three cases to handle: + * 1) If the cast->type has already been loaded AND the type we are adding + * casting info to has not been loaded (it is in this module), THEN we + * replace the cast->type pointer with the type pointer that has already + * been loaded. + * 2) If BOTH types (the one we are adding casting info to, and the + * cast->type) are loaded, THEN the cast info has already been loaded by + * the previous module so we just ignore it. + * 3) Finally, if cast->type has not already been loaded, then we add that + * swig_cast_info to the linked list (because the cast->type) pointer will + * be correct. + * ----------------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* c-mode */ +#endif +#endif + +#if 0 +#define SWIGRUNTIME_DEBUG +#endif + + +SWIGRUNTIME void +SWIG_InitializeModule(void *clientdata) { + size_t i; + swig_module_info *module_head, *iter; + int found, init; + + clientdata = clientdata; + + /* check to see if the circular list has been setup, if not, set it up */ + if (swig_module.next==0) { + /* Initialize the swig_module */ + swig_module.type_initial = swig_type_initial; + swig_module.cast_initial = swig_cast_initial; + swig_module.next = &swig_module; + init = 1; + } else { + init = 0; + } + + /* Try and load any already created modules */ + module_head = SWIG_GetModule(clientdata); + if (!module_head) { + /* This is the first module loaded for this interpreter */ + /* so set the swig module into the interpreter */ + SWIG_SetModule(clientdata, &swig_module); + module_head = &swig_module; + } else { + /* the interpreter has loaded a SWIG module, but has it loaded this one? */ + found=0; + iter=module_head; + do { + if (iter==&swig_module) { + found=1; + break; + } + iter=iter->next; + } while (iter!= module_head); + + /* if the is found in the list, then all is done and we may leave */ + if (found) return; + /* otherwise we must add out module into the list */ + swig_module.next = module_head->next; + module_head->next = &swig_module; + } + + /* When multiple interpeters are used, a module could have already been initialized in + a different interpreter, but not yet have a pointer in this interpreter. + In this case, we do not want to continue adding types... everything should be + set up already */ + if (init == 0) return; + + /* Now work on filling in swig_module.types */ +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: size %d\n", swig_module.size); +#endif + for (i = 0; i < swig_module.size; ++i) { + swig_type_info *type = 0; + swig_type_info *ret; + swig_cast_info *cast; + +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); +#endif + + /* if there is another module already loaded */ + if (swig_module.next != &swig_module) { + type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name); + } + if (type) { + /* Overwrite clientdata field */ +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: found type %s\n", type->name); +#endif + if (swig_module.type_initial[i]->clientdata) { + type->clientdata = swig_module.type_initial[i]->clientdata; +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name); +#endif + } + } else { + type = swig_module.type_initial[i]; + } + + /* Insert casting types */ + cast = swig_module.cast_initial[i]; + while (cast->type) { + /* Don't need to add information already in the list */ + ret = 0; +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: look cast %s\n", cast->type->name); +#endif + if (swig_module.next != &swig_module) { + ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name); +#ifdef SWIGRUNTIME_DEBUG + if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name); +#endif + } + if (ret) { + if (type == swig_module.type_initial[i]) { +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: skip old type %s\n", ret->name); +#endif + cast->type = ret; + ret = 0; + } else { + /* Check for casting already in the list */ + swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type); +#ifdef SWIGRUNTIME_DEBUG + if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name); +#endif + if (!ocast) ret = 0; + } + } + + if (!ret) { +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name); +#endif + if (type->cast) { + type->cast->prev = cast; + cast->next = type->cast; + } + type->cast = cast; + } + cast++; + } + /* Set entry in modules->types array equal to the type */ + swig_module.types[i] = type; + } + swig_module.types[i] = 0; + +#ifdef SWIGRUNTIME_DEBUG + printf("**** SWIG_InitializeModule: Cast List ******\n"); + for (i = 0; i < swig_module.size; ++i) { + int j = 0; + swig_cast_info *cast = swig_module.cast_initial[i]; + printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); + while (cast->type) { + printf("SWIG_InitializeModule: cast type %s\n", cast->type->name); + cast++; + ++j; + } + printf("---- Total casts: %d\n",j); + } + printf("**** SWIG_InitializeModule: Cast List ******\n"); +#endif +} + +/* This function will propagate the clientdata field of type to +* any new swig_type_info structures that have been added into the list +* of equivalent types. It is like calling +* SWIG_TypeClientData(type, clientdata) a second time. +*/ +SWIGRUNTIME void +SWIG_PropagateClientData(void) { + size_t i; + swig_cast_info *equiv; + static int init_run = 0; + + if (init_run) return; + init_run = 1; + + for (i = 0; i < swig_module.size; i++) { + if (swig_module.types[i]->clientdata) { + equiv = swig_module.types[i]->cast; + while (equiv) { + if (!equiv->converter) { + if (equiv->type && !equiv->type->clientdata) + SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata); + } + equiv = equiv->next; + } + } + } +} + +#ifdef __cplusplus +#if 0 +{ + /* c-mode */ +#endif +} +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + /* Python-specific SWIG API */ +#define SWIG_newvarlink() SWIG_Python_newvarlink() +#define SWIG_addvarlink(p, name, get_attr, set_attr) SWIG_Python_addvarlink(p, name, get_attr, set_attr) +#define SWIG_InstallConstants(d, constants) SWIG_Python_InstallConstants(d, constants) + + /* ----------------------------------------------------------------------------- + * global variable support code. + * ----------------------------------------------------------------------------- */ + + typedef struct swig_globalvar { + char *name; /* Name of global variable */ + PyObject *(*get_attr)(void); /* Return the current value */ + int (*set_attr)(PyObject *); /* Set the value */ + struct swig_globalvar *next; + } swig_globalvar; + + typedef struct swig_varlinkobject { + PyObject_HEAD + swig_globalvar *vars; + } swig_varlinkobject; + + SWIGINTERN PyObject * + swig_varlink_repr(swig_varlinkobject *SWIGUNUSEDPARM(v)) { + return PyString_FromString("<Swig global variables>"); + } + + SWIGINTERN PyObject * + swig_varlink_str(swig_varlinkobject *v) { + PyObject *str = PyString_FromString("("); + swig_globalvar *var; + for (var = v->vars; var; var=var->next) { + PyString_ConcatAndDel(&str,PyString_FromString(var->name)); + if (var->next) PyString_ConcatAndDel(&str,PyString_FromString(", ")); + } + PyString_ConcatAndDel(&str,PyString_FromString(")")); + return str; + } + + SWIGINTERN int + swig_varlink_print(swig_varlinkobject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) { + PyObject *str = swig_varlink_str(v); + fprintf(fp,"Swig global variables "); + fprintf(fp,"%s\n", PyString_AsString(str)); + Py_DECREF(str); + return 0; + } + + SWIGINTERN void + swig_varlink_dealloc(swig_varlinkobject *v) { + swig_globalvar *var = v->vars; + while (var) { + swig_globalvar *n = var->next; + free(var->name); + free(var); + var = n; + } + } + + SWIGINTERN PyObject * + swig_varlink_getattr(swig_varlinkobject *v, char *n) { + PyObject *res = NULL; + swig_globalvar *var = v->vars; + while (var) { + if (strcmp(var->name,n) == 0) { + res = (*var->get_attr)(); + break; + } + var = var->next; + } + if (res == NULL && !PyErr_Occurred()) { + PyErr_SetString(PyExc_NameError,"Unknown C global variable"); + } + return res; + } + + SWIGINTERN int + swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p) { + int res = 1; + swig_globalvar *var = v->vars; + while (var) { + if (strcmp(var->name,n) == 0) { + res = (*var->set_attr)(p); + break; + } + var = var->next; + } + if (res == 1 && !PyErr_Occurred()) { + PyErr_SetString(PyExc_NameError,"Unknown C global variable"); + } + return res; + } + + SWIGINTERN PyTypeObject* + swig_varlink_type(void) { + static char varlink__doc__[] = "Swig var link object"; + static PyTypeObject varlink_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp + = { + PyObject_HEAD_INIT(NULL) + 0, /* Number of items in variable part (ob_size) */ + (char *)"swigvarlink", /* Type name (tp_name) */ + sizeof(swig_varlinkobject), /* Basic size (tp_basicsize) */ + 0, /* Itemsize (tp_itemsize) */ + (destructor) swig_varlink_dealloc, /* Deallocator (tp_dealloc) */ + (printfunc) swig_varlink_print, /* Print (tp_print) */ + (getattrfunc) swig_varlink_getattr, /* get attr (tp_getattr) */ + (setattrfunc) swig_varlink_setattr, /* Set attr (tp_setattr) */ + 0, /* tp_compare */ + (reprfunc) swig_varlink_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)swig_varlink_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + varlink__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* tp_iter -> tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + varlink_type = tmp; + varlink_type.ob_type = &PyType_Type; + type_init = 1; + } + return &varlink_type; + } + + /* Create a variable linking object for use later */ + SWIGINTERN PyObject * + SWIG_Python_newvarlink(void) { + swig_varlinkobject *result = PyObject_NEW(swig_varlinkobject, swig_varlink_type()); + if (result) { + result->vars = 0; + } + return ((PyObject*) result); + } + + SWIGINTERN void + SWIG_Python_addvarlink(PyObject *p, char *name, PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p)) { + swig_varlinkobject *v = (swig_varlinkobject *) p; + swig_globalvar *gv = (swig_globalvar *) malloc(sizeof(swig_globalvar)); + if (gv) { + size_t size = strlen(name)+1; + gv->name = (char *)malloc(size); + if (gv->name) { + strncpy(gv->name,name,size); + gv->get_attr = get_attr; + gv->set_attr = set_attr; + gv->next = v->vars; + } + } + v->vars = gv; + } + + SWIGINTERN PyObject * + SWIG_globals(void) { + static PyObject *_SWIG_globals = 0; + if (!_SWIG_globals) _SWIG_globals = SWIG_newvarlink(); + return _SWIG_globals; + } + + /* ----------------------------------------------------------------------------- + * constants/methods manipulation + * ----------------------------------------------------------------------------- */ + + /* Install Constants */ + SWIGINTERN void + SWIG_Python_InstallConstants(PyObject *d, swig_const_info constants[]) { + PyObject *obj = 0; + size_t i; + for (i = 0; constants[i].type; ++i) { + switch(constants[i].type) { + case SWIG_PY_POINTER: + obj = SWIG_NewPointerObj(constants[i].pvalue, *(constants[i]).ptype,0); + break; + case SWIG_PY_BINARY: + obj = SWIG_NewPackedObj(constants[i].pvalue, constants[i].lvalue, *(constants[i].ptype)); + break; + default: + obj = 0; + break; + } + if (obj) { + PyDict_SetItemString(d, constants[i].name, obj); + Py_DECREF(obj); + } + } + } + + /* -----------------------------------------------------------------------------*/ + /* Fix SwigMethods to carry the callback ptrs when needed */ + /* -----------------------------------------------------------------------------*/ + + SWIGINTERN void + SWIG_Python_FixMethods(PyMethodDef *methods, + swig_const_info *const_table, + swig_type_info **types, + swig_type_info **types_initial) { + size_t i; + for (i = 0; methods[i].ml_name; ++i) { + const char *c = methods[i].ml_doc; + if (c && (c = strstr(c, "swig_ptr: "))) { + int j; + swig_const_info *ci = 0; + const char *name = c + 10; + for (j = 0; const_table[j].type; ++j) { + if (strncmp(const_table[j].name, name, + strlen(const_table[j].name)) == 0) { + ci = &(const_table[j]); + break; + } + } + if (ci) { + size_t shift = (ci->ptype) - types; + swig_type_info *ty = types_initial[shift]; + size_t ldoc = (c - methods[i].ml_doc); + size_t lptr = strlen(ty->name)+2*sizeof(void*)+2; + char *ndoc = (char*)malloc(ldoc + lptr + 10); + if (ndoc) { + char *buff = ndoc; + void *ptr = (ci->type == SWIG_PY_POINTER) ? ci->pvalue : 0; + if (ptr) { + strncpy(buff, methods[i].ml_doc, ldoc); + buff += ldoc; + strncpy(buff, "swig_ptr: ", 10); + buff += 10; + SWIG_PackVoidPtr(buff, ptr, ty->name, lptr); + methods[i].ml_doc = ndoc; + } + } + } + } + } + } + +#ifdef __cplusplus +} +#endif + +/* -----------------------------------------------------------------------------* + * Partial Init method + * -----------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" +#endif +SWIGEXPORT void SWIG_init(void) { + PyObject *m, *d; + + /* Fix SwigMethods to carry the callback ptrs when needed */ + SWIG_Python_FixMethods(SwigMethods, swig_const_table, swig_types, swig_type_initial); + + m = Py_InitModule((char *) SWIG_name, SwigMethods); + d = PyModule_GetDict(m); + + SWIG_InitializeModule(0); + SWIG_InstallConstants(d,swig_const_table); + + +} + diff --git a/source4/scripting/python/modules.c b/source4/scripting/python/modules.c new file mode 100644 index 0000000000..0fe15b2fda --- /dev/null +++ b/source4/scripting/python/modules.c @@ -0,0 +1,69 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + 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/>. +*/ + +#include "includes.h" +#include <Python.h> + +extern void init_ldb(void); +extern void init_security(void); +extern void init_registry(void); +extern void init_param(void); +extern void init_misc(void); +extern void init_ldb(void); +extern void init_auth(void); +extern void init_credentials(void); +extern void init_tdb(void); +extern void init_dcerpc(void); +extern void init_events(void); +extern void inituuid(void); +extern void init_net(void); +extern void initecho(void); +extern void initdfs(void); +extern void initdrsuapi(void); +extern void initwinreg(void); +extern void initepmapper(void); +extern void initinitshutdown(void); +extern void initmgmt(void); +extern void initnet(void); +extern void initatsvc(void); +extern void initsamr(void); +extern void initlsa(void); +extern void initsvcctl(void); +extern void initwkssvc(void); +extern void initunixinfo(void); +extern void init_libcli_nbt(void); +extern void init_libcli_smb(void); + +static struct _inittab py_modules[] = { STATIC_LIBPYTHON_MODULES }; + +void py_load_samba_modules(void) +{ + int i; + for (i = 0; i < ARRAY_SIZE(py_modules); i++) { + PyImport_ExtendInittab(&py_modules[i]); + } +} + +void py_update_path(const char *bindir) +{ + char *newpath; + asprintf(&newpath, "%s/python:%s/../scripting/python:%s", bindir, bindir, Py_GetPath()); + PySys_SetPath(newpath); + free(newpath); +} diff --git a/source4/scripting/python/modules.h b/source4/scripting/python/modules.h new file mode 100644 index 0000000000..238c73455f --- /dev/null +++ b/source4/scripting/python/modules.h @@ -0,0 +1,26 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + 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/>. +*/ + +#ifndef __SAMBA_PYTHON_MODULES_H__ +#define __SAMBA_PYTHON_MODULES_H__ + +void py_load_samba_modules(void); +void py_update_path(const char *bindir); + +#endif /* __SAMBA_PYTHON_MODULES_H__ */ diff --git a/source4/scripting/python/pytalloc.c b/source4/scripting/python/pytalloc.c new file mode 100644 index 0000000000..ca476e9604 --- /dev/null +++ b/source4/scripting/python/pytalloc.c @@ -0,0 +1,52 @@ +/* + Unix SMB/CIFS implementation. + Python/Talloc glue + 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/>. +*/ + +#include "includes.h" +#include "scripting/python/pytalloc.h" + +void py_talloc_dealloc(PyObject* self) +{ + py_talloc_Object *obj = (py_talloc_Object *)self; + talloc_free(obj->talloc_ctx); + obj->talloc_ctx = NULL; + PyObject_Del(self); +} + +PyObject *py_talloc_import_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, + void *ptr) +{ + py_talloc_Object *ret = PyObject_New(py_talloc_Object, py_type); + ret->talloc_ctx = talloc_new(NULL); + if (ret->talloc_ctx == NULL) { + return NULL; + } + if (talloc_reference(ret->talloc_ctx, mem_ctx) == NULL) { + return NULL; + } + ret->ptr = ptr; + return (PyObject *)ret; +} + +PyObject *py_talloc_default_repr(PyObject *py_obj) +{ + py_talloc_Object *obj = (py_talloc_Object *)py_obj; + PyTypeObject *type = (PyTypeObject*)PyObject_Type((PyObject *)obj); + + return PyString_FromFormat("<%s talloc object at 0x%x>", type->tp_name, (intptr_t)py_obj); +} diff --git a/source4/scripting/python/pytalloc.h b/source4/scripting/python/pytalloc.h new file mode 100644 index 0000000000..aad5840a67 --- /dev/null +++ b/source4/scripting/python/pytalloc.h @@ -0,0 +1,51 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + 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/>. +*/ + +#ifndef _PY_TALLOC_H_ +#define _PY_TALLOC_H_ + +#include <Python.h> + +typedef struct { + PyObject_HEAD + TALLOC_CTX *talloc_ctx; + void *ptr; +} py_talloc_Object; + +/* Deallocate a py_talloc_Object */ +void py_talloc_dealloc(PyObject* self); + +/* Retrieve the pointer for a py_talloc_object. Like talloc_get_type() + * but for py_talloc_Objects. */ + +/* FIXME: Call PyErr_SetString(PyExc_TypeError, "expected " __STR(type) ") + * when talloc_get_type() returns NULL. */ +#define py_talloc_get_type(py_obj, type) \ + talloc_get_type(py_talloc_get_ptr(py_obj), type) + +#define py_talloc_get_ptr(py_obj) ((py_talloc_Object *)py_obj)->ptr +#define py_talloc_get_mem_ctx(py_obj) ((py_talloc_Object *)py_obj)->talloc_ctx + +PyObject *py_talloc_import_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr); +#define py_talloc_import(py_type, talloc_ptr) py_talloc_import_ex(py_type, talloc_ptr, talloc_ptr) + +/* Sane default implementation of reprfunc. */ +PyObject *py_talloc_default_repr(PyObject *py_obj); + +#endif /* _PY_TALLOC_H_ */ diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py new file mode 100644 index 0000000000..e191227108 --- /dev/null +++ b/source4/scripting/python/samba/__init__.py @@ -0,0 +1,238 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008 +# +# Based on the original in EJS: +# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005 +# +# 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/>. +# + +"""Samba 4.""" + +__docformat__ = "restructuredText" + +import os + +def _in_source_tree(): + """Check whether the script is being run from the source dir. """ + return os.path.exists("%s/../../../samba4-skip" % os.path.dirname(__file__)) + + +# When running, in-tree, make sure bin/python is in the PYTHONPATH +if _in_source_tree(): + import sys + srcdir = "%s/../../.." % os.path.dirname(__file__) + sys.path.append("%s/bin/python" % srcdir) + default_ldb_modules_dir = "%s/bin/modules/ldb" % srcdir +else: + default_ldb_modules_dir = None + + +import ldb +import credentials +import misc + +class Ldb(ldb.Ldb): + """Simple Samba-specific LDB subclass that takes care + of setting up the modules dir, credentials pointers, etc. + + Please note that this is intended to be for all Samba LDB files, + not necessarily the Sam database. For Sam-specific helper + functions see samdb.py. + """ + def __init__(self, url=None, session_info=None, credentials=None, + modules_dir=None, lp=None): + """Open a Samba Ldb file. + + :param url: Optional LDB URL to open + :param session_info: Optional session information + :param credentials: Optional credentials, defaults to anonymous. + :param modules_dir: Modules directory, if not the default. + :param lp: Loadparm object, optional. + + This is different from a regular Ldb file in that the Samba-specific + modules-dir is used by default and that credentials and session_info + can be passed through (required by some modules). + """ + super(Ldb, self).__init__() + + if modules_dir is not None: + self.set_modules_dir(modules_dir) + elif default_ldb_modules_dir is not None: + self.set_modules_dir(default_ldb_modules_dir) + + if credentials is not None: + self.set_credentials(credentials) + + if session_info is not None: + self.set_session_info(session_info) + + assert misc.ldb_register_samba_handlers(self) == 0 + + if lp is not None: + self.set_loadparm(lp) + + def msg(l,text): + print text + #self.set_debug(msg) + + if url is not None: + self.connect(url) + + + set_credentials = misc.ldb_set_credentials + set_session_info = misc.ldb_set_session_info + set_loadparm = misc.ldb_set_loadparm + + def searchone(self, attribute, basedn=None, expression=None, + scope=ldb.SCOPE_BASE): + """Search for one attribute as a string. + + :param basedn: BaseDN for the search. + :param attribute: Name of the attribute + :param expression: Optional search expression. + :param scope: Search scope (defaults to base). + :return: Value of attribute as a string or None if it wasn't found. + """ + res = self.search(basedn, scope, expression, [attribute]) + if len(res) != 1 or res[0][attribute] is None: + return None + values = set(res[0][attribute]) + assert len(values) == 1 + return self.schema_format_value(attribute, values.pop()) + + def erase(self): + """Erase this ldb, removing all records.""" + # delete the specials + for attr in ["@INDEXLIST", "@ATTRIBUTES", "@SUBCLASSES", "@MODULES", + "@OPTIONS", "@PARTITION", "@KLUDGEACL"]: + try: + self.delete(attr) + except ldb.LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): + # Ignore missing dn errors + pass + + basedn = "" + # and the rest + for msg in self.search(basedn, ldb.SCOPE_SUBTREE, + "(&(|(objectclass=*)(distinguishedName=*))(!(distinguishedName=@BASEINFO)))", + ["distinguishedName"]): + try: + self.delete(msg.dn) + except ldb.LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): + # Ignore no such object errors + pass + + res = self.search(basedn, ldb.SCOPE_SUBTREE, "(&(|(objectclass=*)(distinguishedName=*))(!(distinguishedName=@BASEINFO)))", ["distinguishedName"]) + assert len(res) == 0 + + def erase_partitions(self): + """Erase an ldb, removing all records.""" + res = self.search("", ldb.SCOPE_BASE, "(objectClass=*)", + ["namingContexts"]) + assert len(res) == 1 + if not "namingContexts" in res[0]: + return + for basedn in res[0]["namingContexts"]: + previous_remaining = 1 + current_remaining = 0 + + k = 0 + while ++k < 10 and (previous_remaining != current_remaining): + # and the rest + try: + res2 = self.search(basedn, ldb.SCOPE_SUBTREE, "(|(objectclass=*)(distinguishedName=*))", ["distinguishedName"]) + except ldb.LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): + # Ignore missing dn errors + return + + previous_remaining = current_remaining + current_remaining = len(res2) + for msg in res2: + try: + self.delete(msg.dn) + # Ignore no such object errors + except ldb.LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): + pass + # Ignore not allowed on non leaf errors + except ldb.LdbError, (LDB_ERR_NOT_ALLOWED_ON_NON_LEAF, _): + pass + + def load_ldif_file_add(self, ldif_path): + """Load a LDIF file. + + :param ldif_path: Path to LDIF file. + """ + self.add_ldif(open(ldif_path, 'r').read()) + + def add_ldif(self, ldif): + """Add data based on a LDIF string. + + :param ldif: LDIF text. + """ + for changetype, msg in self.parse_ldif(ldif): + assert changetype == ldb.CHANGETYPE_NONE + self.add(msg) + + def modify_ldif(self, ldif): + """Modify database based on a LDIF string. + + :param ldif: LDIF text. + """ + for changetype, msg in self.parse_ldif(ldif): + self.modify(msg) + + +def substitute_var(text, values): + """substitute strings of the form ${NAME} in str, replacing + with substitutions from subobj. + + :param text: Text in which to subsitute. + :param values: Dictionary with keys and values. + """ + + for (name, value) in values.items(): + assert isinstance(name, str), "%r is not a string" % name + assert isinstance(value, str), "Value %r for %s is not a string" % (value, name) + text = text.replace("${%s}" % name, value) + + return text + + +def check_all_substituted(text): + """Make sure that all substitution variables in a string have been replaced. + If not, raise an exception. + + :param text: The text to search for substitution variables + """ + if not "${" in text: + return + + var_start = text.find("${") + var_end = text.find("}", var_start) + + raise Exception("Not all variables substituted: %s" % text[var_start:var_end+1]) + + +def valid_netbios_name(name): + """Check whether a name is valid as a NetBIOS name. """ + # FIXME: There are probably more constraints here. + # crh has a paragraph on this in his book (1.4.1.1) + if len(name) > 15: + return False + return True + +version = misc.version diff --git a/source4/scripting/python/samba/getopt.py b/source4/scripting/python/samba/getopt.py new file mode 100644 index 0000000000..c12245f6c5 --- /dev/null +++ b/source4/scripting/python/samba/getopt.py @@ -0,0 +1,116 @@ +#!/usr/bin/python + +# Samba-specific bits for optparse +# 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/>. +# + +"""Support for parsing Samba-related command-line options.""" + +import optparse +from credentials import Credentials, AUTO_USE_KERBEROS, DONT_USE_KERBEROS, MUST_USE_KERBEROS +from hostconfig import Hostconfig + +__docformat__ = "restructuredText" + +class SambaOptions(optparse.OptionGroup): + """General Samba-related command line options.""" + def __init__(self, parser): + optparse.OptionGroup.__init__(self, parser, "Samba Common Options") + self.add_option("-s", "--configfile", action="callback", + type=str, metavar="FILE", help="Configuration file", + callback=self._load_configfile) + self._configfile = None + + def get_loadparm_path(self): + """Return the path to the smb.conf file specified on the command line. """ + return self._configfile + + def _load_configfile(self, option, opt_str, arg, parser): + self._configfile = arg + + def get_loadparm(self): + """Return a loadparm object with data specified on the command line. """ + import os, param + lp = param.LoadParm() + if self._configfile is not None: + lp.load(self._configfile) + elif os.getenv("SMB_CONF_PATH") is not None: + lp.load(os.getenv("SMB_CONF_PATH")) + else: + lp.load_default() + return lp + + def get_hostconfig(self): + return Hostconfig(self.get_loadparm()) + + +class VersionOptions(optparse.OptionGroup): + """Command line option for printing Samba version.""" + def __init__(self, parser): + optparse.OptionGroup.__init__(self, parser, "Version Options") + + +class CredentialsOptions(optparse.OptionGroup): + """Command line options for specifying credentials.""" + def __init__(self, parser): + self.no_pass = False + optparse.OptionGroup.__init__(self, parser, "Credentials Options") + self.add_option("--simple-bind-dn", metavar="DN", action="callback", + callback=self._set_simple_bind_dn, type=str, + help="DN to use for a simple bind") + self.add_option("--password", metavar="PASSWORD", action="callback", + help="Password", type=str, callback=self._set_password) + self.add_option("-U", "--username", metavar="USERNAME", + action="callback", type=str, + help="Username", callback=self._parse_username) + self.add_option("-W", "--workgroup", metavar="WORKGROUP", + action="callback", type=str, + help="Workgroup", callback=self._parse_workgroup) + self.add_option("-N", "--no-pass", action="store_true", + help="Don't ask for a password") + self.add_option("-k", "--kerberos", metavar="KERBEROS", + action="callback", type=str, + help="Use Kerberos", callback=self._set_kerberos) + self.creds = Credentials() + + def _parse_username(self, option, opt_str, arg, parser): + self.creds.parse_string(arg) + + def _parse_workgroup(self, option, opt_str, arg, parser): + self.creds.set_domain(arg) + + def _set_password(self, option, opt_str, arg, parser): + self.creds.set_password(arg) + + def _set_kerberos(self, option, opt_str, arg, parser): + if bool(arg) or arg.lower() == "yes": + self.creds.set_kerberos_state(MUST_USE_KERBEROS) + else: + self.creds.set_kerberos_state(DONT_USE_KERBEROS) + + def _set_simple_bind_dn(self, option, opt_str, arg, parser): + self.creds.set_bind_dn(arg) + + def get_credentials(self, lp): + """Obtain the credentials set on the command-line. + + :param lp: Loadparm object to use. + :return: Credentials object + """ + self.creds.guess(lp) + if not self.no_pass: + self.creds.set_cmdline_callbacks() + return self.creds diff --git a/source4/scripting/python/samba/hostconfig.py b/source4/scripting/python/samba/hostconfig.py new file mode 100644 index 0000000000..313e3420b0 --- /dev/null +++ b/source4/scripting/python/samba/hostconfig.py @@ -0,0 +1,33 @@ +#!/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/>. +# + +from samdb import SamDB + +class Hostconfig(object): + """Aggregate object that contains all information about the configuration + of a Samba host.""" + + def __init__(self, lp): + self.lp = lp + + def get_samdb(self, session_info, credentials): + return SamDB(url=self.lp.get("sam database"), + session_info=session_info, credentials=credentials, + lp=self.lp) + diff --git a/source4/scripting/python/samba/idmap.py b/source4/scripting/python/samba/idmap.py new file mode 100644 index 0000000000..755ec52c7b --- /dev/null +++ b/source4/scripting/python/samba/idmap.py @@ -0,0 +1,82 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) 2008 Kai Blin <kai@samba.org> +# +# +# 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/>. +# + +"""Convenience functions for using the idmap database.""" + +__docformat__ = "restructuredText" + +import samba +import misc +import ldb + +class IDmapDB(samba.Ldb): + """The IDmap database.""" + + # Mappings for ID_TYPE_UID, ID_TYPE_GID and ID_TYPE_BOTH + TYPE_UID = 1 + TYPE_GID = 2 + TYPE_BOTH = 3 + + def __init__(self, url=None, session_info=None, credentials=None, + modules_dir=None, lp=None): + """Open the IDmap Database. + + :param url: URL of the database. + """ + self.lp = lp + + super(IDmapDB, self).__init__(session_info=session_info, credentials=credentials, + modules_dir=modules_dir, lp=lp) + if url: + self.connect(url) + else: + self.connect(lp.get("idmap database")) + + def connect(self, url): + super(IDmapDB, self).connect(misc.private_path(self.lp, url)) + + def setup_name_mapping(self, sid, type, unixid): + """Setup a mapping between a sam name and a unix name. + + :param sid: SID of the NT-side of the mapping. + :param unixname: Unix name to map to. + """ + type_string = "" + if type == self.TYPE_UID: + type_string = "ID_TYPE_UID" + elif type == self.TYPE_GID: + type_string = "ID_TYPE_GID" + elif type == self.TYPE_BOTH: + type_string = "ID_TYPE_BOTH" + else: + return + + mod = """ +dn: CN=%s +xidNumber: %s +objectSid: %s +objectClass: sidMap +type: %s +cn: %s + +""" % (sid, unixid, sid, type_string, sid) + self.add(self.parse_ldif(mod).next()[1]) + + diff --git a/source4/scripting/python/samba/ndr.py b/source4/scripting/python/samba/ndr.py new file mode 100644 index 0000000000..e718ff3422 --- /dev/null +++ b/source4/scripting/python/samba/ndr.py @@ -0,0 +1,28 @@ +#!/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/>. +# + +def ndr_pack(object): + return object.__ndr_pack__() + + +def ndr_unpack(cls, data): + object = cls() + object.__ndr_unpack__(data) + return object diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py new file mode 100644 index 0000000000..68f61532ad --- /dev/null +++ b/source4/scripting/python/samba/provision.py @@ -0,0 +1,1531 @@ +# +# Unix SMB/CIFS implementation. +# backend code for provisioning a Samba4 server + +# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008 +# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008 +# +# Based on the original in EJS: +# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005 +# +# 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/>. +# + +"""Functions for setting up a Samba configuration.""" + +from base64 import b64encode +import os +import pwd +import grp +import time +import uuid, misc +import socket +import param +import registry +import samba +from auth import system_session +from samba import Ldb, substitute_var, valid_netbios_name, check_all_substituted +from samba.samdb import SamDB +from samba.idmap import IDmapDB +import security +import urllib +from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \ + LDB_ERR_NO_SUCH_OBJECT, timestring, CHANGETYPE_MODIFY, CHANGETYPE_NONE + +__docformat__ = "restructuredText" + +DEFAULTSITE = "Default-First-Site-Name" + +class InvalidNetbiosName(Exception): + """A specified name was not a valid NetBIOS name.""" + def __init__(self, name): + super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name) + + +class ProvisionPaths(object): + def __init__(self): + self.shareconf = None + self.hklm = None + self.hkcu = None + self.hkcr = None + self.hku = None + self.hkpd = None + self.hkpt = None + self.samdb = None + self.idmapdb = None + self.secrets = None + self.keytab = None + self.dns_keytab = None + self.dns = None + self.winsdb = None + self.private_dir = None + self.ldapdir = None + self.slapdconf = None + self.modulesconf = None + self.memberofconf = None + self.fedoradsinf = None + self.fedoradspartitions = None + self.olmmron = None + self.olmmrserveridsconf = None + self.olmmrsyncreplconf = None + +class ProvisionNames(object): + def __init__(self): + self.rootdn = None + self.domaindn = None + self.configdn = None + self.schemadn = None + self.ldapmanagerdn = None + self.dnsdomain = None + self.realm = None + self.netbiosname = None + self.domain = None + self.hostname = None + self.sitename = None + self.smbconf = None + + +class ProvisionResult(object): + def __init__(self): + self.paths = None + self.domaindn = None + self.lp = None + self.samdb = None + +def check_install(lp, session_info, credentials): + """Check whether the current install seems ok. + + :param lp: Loadparm context + :param session_info: Session information + :param credentials: Credentials + """ + if lp.get("realm") == "": + raise Exception("Realm empty") + ldb = Ldb(lp.get("sam database"), session_info=session_info, + credentials=credentials, lp=lp) + if len(ldb.search("(cn=Administrator)")) != 1: + raise "No administrator account found" + + +def findnss(nssfn, names): + """Find a user or group from a list of possibilities. + + :param nssfn: NSS Function to try (should raise KeyError if not found) + :param names: Names to check. + :return: Value return by first names list. + """ + for name in names: + try: + return nssfn(name) + except KeyError: + pass + raise KeyError("Unable to find user/group %r" % names) + + +findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2] +findnss_gid = lambda names: findnss(grp.getgrnam, names)[2] + + +def read_and_sub_file(file, subst_vars): + """Read a file and sub in variables found in it + + :param file: File to be read (typically from setup directory) + param subst_vars: Optional variables to subsitute in the file. + """ + data = open(file, 'r').read() + if subst_vars is not None: + data = substitute_var(data, subst_vars) + check_all_substituted(data) + return data + + +def setup_add_ldif(ldb, ldif_path, subst_vars=None): + """Setup a ldb in the private dir. + + :param ldb: LDB file to import data into + :param ldif_path: Path of the LDIF file to load + :param subst_vars: Optional variables to subsitute in LDIF. + """ + assert isinstance(ldif_path, str) + + data = read_and_sub_file(ldif_path, subst_vars) + ldb.add_ldif(data) + + +def setup_modify_ldif(ldb, ldif_path, subst_vars=None): + """Modify a ldb in the private dir. + + :param ldb: LDB object. + :param ldif_path: LDIF file path. + :param subst_vars: Optional dictionary with substitution variables. + """ + data = read_and_sub_file(ldif_path, subst_vars) + + ldb.modify_ldif(data) + + +def setup_ldb(ldb, ldif_path, subst_vars): + """Import a LDIF a file into a LDB handle, optionally substituting variables. + + :note: Either all LDIF data will be added or none (using transactions). + + :param ldb: LDB file to import into. + :param ldif_path: Path to the LDIF file. + :param subst_vars: Dictionary with substitution variables. + """ + assert ldb is not None + ldb.transaction_start() + try: + setup_add_ldif(ldb, ldif_path, subst_vars) + except: + ldb.transaction_cancel() + raise + ldb.transaction_commit() + + +def setup_file(template, fname, subst_vars): + """Setup a file in the private dir. + + :param template: Path of the template file. + :param fname: Path of the file to create. + :param subst_vars: Substitution variables. + """ + f = fname + + if os.path.exists(f): + os.unlink(f) + + data = read_and_sub_file(template, subst_vars) + open(f, 'w').write(data) + + +def provision_paths_from_lp(lp, dnsdomain): + """Set the default paths for provisioning. + + :param lp: Loadparm context. + :param dnsdomain: DNS Domain name + """ + paths = ProvisionPaths() + paths.private_dir = lp.get("private dir") + paths.keytab = "secrets.keytab" + paths.dns_keytab = "dns.keytab" + + paths.shareconf = os.path.join(paths.private_dir, "share.ldb") + paths.samdb = os.path.join(paths.private_dir, lp.get("sam database") or "samdb.ldb") + paths.idmapdb = os.path.join(paths.private_dir, lp.get("idmap database") or "idmap.ldb") + paths.secrets = os.path.join(paths.private_dir, lp.get("secrets database") or "secrets.ldb") + paths.templates = os.path.join(paths.private_dir, "templates.ldb") + paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone") + paths.namedconf = os.path.join(paths.private_dir, "named.conf") + paths.namedtxt = os.path.join(paths.private_dir, "named.txt") + paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf") + paths.winsdb = os.path.join(paths.private_dir, "wins.ldb") + paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi") + paths.phpldapadminconfig = os.path.join(paths.private_dir, + "phpldapadmin-config.php") + paths.ldapdir = os.path.join(paths.private_dir, + "ldap") + paths.slapdconf = os.path.join(paths.ldapdir, + "slapd.conf") + paths.modulesconf = os.path.join(paths.ldapdir, + "modules.conf") + paths.memberofconf = os.path.join(paths.ldapdir, + "memberof.conf") + paths.fedoradsinf = os.path.join(paths.ldapdir, + "fedorads.inf") + paths.fedoradspartitions = os.path.join(paths.ldapdir, + "fedorads-partitions.ldif") + paths.olmmrserveridsconf = os.path.join(paths.ldapdir, + "mmr_serverids.conf") + paths.olmmrsyncreplconf = os.path.join(paths.ldapdir, + "mmr_syncrepl.conf") + paths.hklm = "hklm.ldb" + paths.hkcr = "hkcr.ldb" + paths.hkcu = "hkcu.ldb" + paths.hku = "hku.ldb" + paths.hkpd = "hkpd.ldb" + paths.hkpt = "hkpt.ldb" + + paths.sysvol = lp.get("path", "sysvol") + + paths.netlogon = lp.get("path", "netlogon") + + paths.smbconf = lp.configfile() + + return paths + + +def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, serverrole=None, + rootdn=None, domaindn=None, configdn=None, schemadn=None, serverdn=None, + sitename=None): + """Guess configuration settings to use.""" + + if hostname is None: + hostname = socket.gethostname().split(".")[0].lower() + + netbiosname = hostname.upper() + if not valid_netbios_name(netbiosname): + raise InvalidNetbiosName(netbiosname) + + hostname = hostname.lower() + + if dnsdomain is None: + dnsdomain = lp.get("realm") + + if serverrole is None: + serverrole = lp.get("server role") + + assert dnsdomain is not None + realm = dnsdomain.upper() + + if lp.get("realm").upper() != realm: + raise Exception("realm '%s' in %s must match chosen realm '%s'" % + (lp.get("realm"), lp.configfile(), realm)) + + dnsdomain = dnsdomain.lower() + + if serverrole == "domain controller": + if domain is None: + domain = lp.get("workgroup") + if domaindn is None: + domaindn = "DC=" + dnsdomain.replace(".", ",DC=") + if lp.get("workgroup").upper() != domain.upper(): + raise Exception("workgroup '%s' in smb.conf must match chosen domain '%s'", + lp.get("workgroup"), domain) + else: + domain = netbiosname + if domaindn is None: + domaindn = "CN=" + netbiosname + + assert domain is not None + domain = domain.upper() + if not valid_netbios_name(domain): + raise InvalidNetbiosName(domain) + + if rootdn is None: + rootdn = domaindn + + if configdn is None: + configdn = "CN=Configuration," + rootdn + if schemadn is None: + schemadn = "CN=Schema," + configdn + + if sitename is None: + sitename=DEFAULTSITE + + names = ProvisionNames() + names.rootdn = rootdn + names.domaindn = domaindn + names.configdn = configdn + names.schemadn = schemadn + names.ldapmanagerdn = "CN=Manager," + rootdn + names.dnsdomain = dnsdomain + names.domain = domain + names.realm = realm + names.netbiosname = netbiosname + names.hostname = hostname + names.sitename = sitename + names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (netbiosname, sitename, configdn) + + return names + + +def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, + targetdir): + if hostname is None: + hostname = socket.gethostname().split(".")[0].lower() + + if serverrole is None: + serverrole = "standalone" + + assert serverrole in ("domain controller", "member server", "standalone") + if serverrole == "domain controller": + smbconfsuffix = "dc" + elif serverrole == "member server": + smbconfsuffix = "member" + elif serverrole == "standalone": + smbconfsuffix = "standalone" + + assert domain is not None + assert realm is not None + + default_lp = param.LoadParm() + #Load non-existant file + default_lp.load(smbconf) + + if targetdir is not None: + privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private")) + lockdir_line = "lock dir = " + os.path.abspath(targetdir) + + default_lp.set("lock dir", os.path.abspath(targetdir)) + else: + privatedir_line = "" + lockdir_line = "" + + sysvol = os.path.join(default_lp.get("lock dir"), "sysvol") + netlogon = os.path.join(sysvol, realm.lower(), "scripts") + + setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), + smbconf, { + "HOSTNAME": hostname, + "DOMAIN": domain, + "REALM": realm, + "SERVERROLE": serverrole, + "NETLOGONPATH": netlogon, + "SYSVOLPATH": sysvol, + "PRIVATEDIR_LINE": privatedir_line, + "LOCKDIR_LINE": lockdir_line + }) + + + +def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid, + users_gid, wheel_gid): + """setup reasonable name mappings for sam names to unix names. + + :param samdb: SamDB object. + :param idmap: IDmap db object. + :param sid: The domain sid. + :param domaindn: The domain DN. + :param root_uid: uid of the UNIX root user. + :param nobody_uid: uid of the UNIX nobody user. + :param users_gid: gid of the UNIX users group. + :param wheel_gid: gid of the UNIX wheel group.""" + # add some foreign sids if they are not present already + samdb.add_foreign(domaindn, "S-1-5-7", "Anonymous") + samdb.add_foreign(domaindn, "S-1-1-0", "World") + samdb.add_foreign(domaindn, "S-1-5-2", "Network") + samdb.add_foreign(domaindn, "S-1-5-18", "System") + samdb.add_foreign(domaindn, "S-1-5-11", "Authenticated Users") + + idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid) + idmap.setup_name_mapping("S-1-5-32-544", idmap.TYPE_GID, wheel_gid) + + idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid) + idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid) + + +def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, + credentials, names, + serverrole, ldap_backend=None, + ldap_backend_type=None, erase=False): + """Setup the partitions for the SAM database. + + Alternatively, provision() may call this, and then populate the database. + + :note: This will wipe the Sam Database! + + :note: This function always removes the local SAM LDB file. The erase + parameter controls whether to erase the existing data, which + may not be stored locally but in LDAP. + """ + assert session_info is not None + + samdb = SamDB(samdb_path, session_info=session_info, + credentials=credentials, lp=lp) + + # Wipes the database + try: + samdb.erase() + except: + os.unlink(samdb_path) + + samdb = SamDB(samdb_path, session_info=session_info, + credentials=credentials, lp=lp) + + #Add modules to the list to activate them by default + #beware often order is important + # + # Some Known ordering constraints: + # - rootdse must be first, as it makes redirects from "" -> cn=rootdse + # - objectclass must be before password_hash, because password_hash checks + # that the objectclass is of type person (filled in by objectclass + # module when expanding the objectclass list) + # - partition must be last + # - each partition has its own module list then + modules_list = ["rootdse", + "paged_results", + "ranged_results", + "anr", + "server_sort", + "extended_dn", + "asq", + "rdn_name", + "objectclass", + "samldb", + "kludge_acl", + "operational"] + tdb_modules_list = [ + "subtree_rename", + "subtree_delete", + "linked_attributes"] + modules_list2 = ["show_deleted", + "partition"] + + domaindn_ldb = "users.ldb" + if ldap_backend is not None: + domaindn_ldb = ldap_backend + configdn_ldb = "configuration.ldb" + if ldap_backend is not None: + configdn_ldb = ldap_backend + schemadn_ldb = "schema.ldb" + if ldap_backend is not None: + schema_ldb = ldap_backend + schemadn_ldb = ldap_backend + + if ldap_backend_type == "fedora-ds": + backend_modules = ["nsuniqueid", "paged_searches"] + # We can handle linked attributes here, as we don't have directory-side subtree operations + tdb_modules_list = ["linked_attributes"] + elif ldap_backend_type == "openldap": + backend_modules = ["normalise", "entryuuid", "paged_searches"] + # OpenLDAP handles subtree renames, so we don't want to do any of these things + tdb_modules_list = None + elif ldap_backend is not None: + raise "LDAP Backend specified, but LDAP Backend Type not specified" + elif serverrole == "domain controller": + backend_modules = ["repl_meta_data"] + else: + backend_modules = ["objectguid"] + + if tdb_modules_list is None: + tdb_modules_list_as_string = "" + else: + tdb_modules_list_as_string = ","+",".join(tdb_modules_list) + + samdb.transaction_start() + try: + setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), { + "SCHEMADN": names.schemadn, + "SCHEMADN_LDB": schemadn_ldb, + "SCHEMADN_MOD2": ",objectguid", + "CONFIGDN": names.configdn, + "CONFIGDN_LDB": configdn_ldb, + "DOMAINDN": names.domaindn, + "DOMAINDN_LDB": domaindn_ldb, + "SCHEMADN_MOD": "schema_fsmo,instancetype", + "CONFIGDN_MOD": "naming_fsmo,instancetype", + "DOMAINDN_MOD": "pdc_fsmo,password_hash,instancetype", + "MODULES_LIST": ",".join(modules_list), + "TDB_MODULES_LIST": tdb_modules_list_as_string, + "MODULES_LIST2": ",".join(modules_list2), + "BACKEND_MOD": ",".join(backend_modules), + }) + + except: + samdb.transaction_cancel() + raise + + samdb.transaction_commit() + + samdb = SamDB(samdb_path, session_info=session_info, + credentials=credentials, lp=lp) + + samdb.transaction_start() + try: + message("Setting up sam.ldb attributes") + samdb.load_ldif_file_add(setup_path("provision_init.ldif")) + + message("Setting up sam.ldb rootDSE") + setup_samdb_rootdse(samdb, setup_path, names) + + if erase: + message("Erasing data from partitions") + samdb.erase_partitions() + + except: + samdb.transaction_cancel() + raise + + samdb.transaction_commit() + + return samdb + + +def secretsdb_become_dc(secretsdb, setup_path, domain, realm, dnsdomain, + netbiosname, domainsid, keytab_path, samdb_url, + dns_keytab_path, dnspass, machinepass): + """Add DC-specific bits to a secrets database. + + :param secretsdb: Ldb Handle to the secrets database + :param setup_path: Setup path function + :param machinepass: Machine password + """ + setup_ldb(secretsdb, setup_path("secrets_dc.ldif"), { + "MACHINEPASS_B64": b64encode(machinepass), + "DOMAIN": domain, + "REALM": realm, + "DNSDOMAIN": dnsdomain, + "DOMAINSID": str(domainsid), + "SECRETS_KEYTAB": keytab_path, + "NETBIOSNAME": netbiosname, + "SAM_LDB": samdb_url, + "DNS_KEYTAB": dns_keytab_path, + "DNSPASS_B64": b64encode(dnspass), + }) + + +def setup_secretsdb(path, setup_path, session_info, credentials, lp): + """Setup the secrets database. + + :param path: Path to the secrets database. + :param setup_path: Get the path to a setup file. + :param session_info: Session info. + :param credentials: Credentials + :param lp: Loadparm context + :return: LDB handle for the created secrets database + """ + if os.path.exists(path): + os.unlink(path) + secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials, + lp=lp) + secrets_ldb.erase() + secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif")) + secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials, + lp=lp) + secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif")) + + if credentials is not None and credentials.authentication_requested(): + if credentials.get_bind_dn() is not None: + setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), { + "LDAPMANAGERDN": credentials.get_bind_dn(), + "LDAPMANAGERPASS_B64": b64encode(credentials.get_password()) + }) + else: + setup_add_ldif(secrets_ldb, setup_path("secrets_sasl_ldap.ldif"), { + "LDAPADMINUSER": credentials.get_username(), + "LDAPADMINREALM": credentials.get_realm(), + "LDAPADMINPASS_B64": b64encode(credentials.get_password()) + }) + + return secrets_ldb + + +def setup_templatesdb(path, setup_path, session_info, credentials, lp): + """Setup the templates database. + + :param path: Path to the database. + :param setup_path: Function for obtaining the path to setup files. + :param session_info: Session info + :param credentials: Credentials + :param lp: Loadparm context + """ + templates_ldb = SamDB(path, session_info=session_info, + credentials=credentials, lp=lp) + # Wipes the database + try: + templates_ldb.erase() + except: + os.unlink(path) + + templates_ldb.load_ldif_file_add(setup_path("provision_templates_init.ldif")) + + templates_ldb = SamDB(path, session_info=session_info, + credentials=credentials, lp=lp) + + templates_ldb.load_ldif_file_add(setup_path("provision_templates.ldif")) + + +def setup_registry(path, setup_path, session_info, credentials, lp): + """Setup the registry. + + :param path: Path to the registry database + :param setup_path: Function that returns the path to a setup. + :param session_info: Session information + :param credentials: Credentials + :param lp: Loadparm context + """ + reg = registry.Registry() + hive = registry.open_ldb(path, session_info=session_info, + credentials=credentials, lp_ctx=lp) + reg.mount_hive(hive, "HKEY_LOCAL_MACHINE") + provision_reg = setup_path("provision.reg") + assert os.path.exists(provision_reg) + reg.diff_apply(provision_reg) + + +def setup_idmapdb(path, setup_path, session_info, credentials, lp): + """Setup the idmap database. + + :param path: path to the idmap database + :param setup_path: Function that returns a path to a setup file + :param session_info: Session information + :param credentials: Credentials + :param lp: Loadparm context + """ + if os.path.exists(path): + os.unlink(path) + + idmap_ldb = IDmapDB(path, session_info=session_info, + credentials=credentials, lp=lp) + + idmap_ldb.erase() + idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif")) + return idmap_ldb + + +def setup_samdb_rootdse(samdb, setup_path, names): + """Setup the SamDB rootdse. + + :param samdb: Sam Database handle + :param setup_path: Obtain setup path + """ + setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), { + "SCHEMADN": names.schemadn, + "NETBIOSNAME": names.netbiosname, + "DNSDOMAIN": names.dnsdomain, + "REALM": names.realm, + "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain), + "DOMAINDN": names.domaindn, + "ROOTDN": names.rootdn, + "CONFIGDN": names.configdn, + "SERVERDN": names.serverdn, + }) + + +def setup_self_join(samdb, names, + machinepass, dnspass, + domainsid, invocationid, setup_path, + policyguid): + """Join a host to its own domain.""" + assert isinstance(invocationid, str) + setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), { + "CONFIGDN": names.configdn, + "SCHEMADN": names.schemadn, + "DOMAINDN": names.domaindn, + "SERVERDN": names.serverdn, + "INVOCATIONID": invocationid, + "NETBIOSNAME": names.netbiosname, + "DEFAULTSITE": names.sitename, + "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain), + "MACHINEPASS_B64": b64encode(machinepass), + "DNSPASS_B64": b64encode(dnspass), + "REALM": names.realm, + "DOMAIN": names.domain, + "DNSDOMAIN": names.dnsdomain}) + setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), { + "POLICYGUID": policyguid, + "DNSDOMAIN": names.dnsdomain, + "DOMAINSID": str(domainsid), + "DOMAINDN": names.domaindn}) + + +def setup_samdb(path, setup_path, session_info, credentials, lp, + names, message, + domainsid, aci, domainguid, policyguid, + fill, adminpass, krbtgtpass, + machinepass, invocationid, dnspass, + serverrole, ldap_backend=None, + ldap_backend_type=None): + """Setup a complete SAM Database. + + :note: This will wipe the main SAM database file! + """ + + erase = (fill != FILL_DRS) + + # Also wipes the database + setup_samdb_partitions(path, setup_path, message=message, lp=lp, + credentials=credentials, session_info=session_info, + names=names, + ldap_backend=ldap_backend, serverrole=serverrole, + ldap_backend_type=ldap_backend_type, erase=erase) + + samdb = SamDB(path, session_info=session_info, + credentials=credentials, lp=lp) + + message("Pre-loading the Samba 4 and AD schema") + samdb.set_domain_sid(domainsid) + if serverrole == "domain controller": + samdb.set_invocation_id(invocationid) + + load_schema(setup_path, samdb, names.schemadn, names.netbiosname, + names.configdn, names.sitename, names.serverdn, + names.hostname) + + samdb.transaction_start() + + try: + message("Adding DomainDN: %s (permitted to fail)" % names.domaindn) + if serverrole == "domain controller": + domain_oc = "domainDNS" + else: + domain_oc = "samba4LocalDomain" + + setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), { + "DOMAINDN": names.domaindn, + "ACI": aci, + "DOMAIN_OC": domain_oc + }) + + message("Modifying DomainDN: " + names.domaindn + "") + if domainguid is not None: + domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % domainguid + else: + domainguid_mod = "" + + setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), { + "LDAPTIME": timestring(int(time.time())), + "DOMAINSID": str(domainsid), + "SCHEMADN": names.schemadn, + "NETBIOSNAME": names.netbiosname, + "DEFAULTSITE": names.sitename, + "CONFIGDN": names.configdn, + "SERVERDN": names.serverdn, + "POLICYGUID": policyguid, + "DOMAINDN": names.domaindn, + "DOMAINGUID_MOD": domainguid_mod, + }) + + message("Adding configuration container (permitted to fail)") + setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), { + "CONFIGDN": names.configdn, + "ACI": aci, + }) + message("Modifying configuration container") + setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), { + "CONFIGDN": names.configdn, + "SCHEMADN": names.schemadn, + }) + + message("Adding schema container (permitted to fail)") + setup_add_ldif(samdb, setup_path("provision_schema_basedn.ldif"), { + "SCHEMADN": names.schemadn, + "ACI": aci, + }) + message("Modifying schema container") + + prefixmap = open(setup_path("prefixMap.txt"), 'r').read() + + setup_modify_ldif(samdb, + setup_path("provision_schema_basedn_modify.ldif"), { + "SCHEMADN": names.schemadn, + "NETBIOSNAME": names.netbiosname, + "DEFAULTSITE": names.sitename, + "CONFIGDN": names.configdn, + "SERVERDN": names.serverdn, + "PREFIXMAP_B64": b64encode(prefixmap) + }) + + message("Setting up sam.ldb Samba4 schema") + setup_add_ldif(samdb, setup_path("schema_samba4.ldif"), + {"SCHEMADN": names.schemadn }) + message("Setting up sam.ldb AD schema") + setup_add_ldif(samdb, setup_path("schema.ldif"), + {"SCHEMADN": names.schemadn}) + + message("Setting up sam.ldb configuration data") + setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), { + "CONFIGDN": names.configdn, + "NETBIOSNAME": names.netbiosname, + "DEFAULTSITE": names.sitename, + "DNSDOMAIN": names.dnsdomain, + "DOMAIN": names.domain, + "SCHEMADN": names.schemadn, + "DOMAINDN": names.domaindn, + "SERVERDN": names.serverdn + }) + + message("Setting up display specifiers") + setup_add_ldif(samdb, setup_path("display_specifiers.ldif"), + {"CONFIGDN": names.configdn}) + + message("Adding users container (permitted to fail)") + setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), { + "DOMAINDN": names.domaindn}) + message("Modifying users container") + setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), { + "DOMAINDN": names.domaindn}) + message("Adding computers container (permitted to fail)") + setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), { + "DOMAINDN": names.domaindn}) + message("Modifying computers container") + setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), { + "DOMAINDN": names.domaindn}) + message("Setting up sam.ldb data") + setup_add_ldif(samdb, setup_path("provision.ldif"), { + "DOMAINDN": names.domaindn, + "NETBIOSNAME": names.netbiosname, + "DEFAULTSITE": names.sitename, + "CONFIGDN": names.configdn, + "SERVERDN": names.serverdn + }) + + if fill == FILL_FULL: + message("Setting up sam.ldb users and groups") + setup_add_ldif(samdb, setup_path("provision_users.ldif"), { + "DOMAINDN": names.domaindn, + "DOMAINSID": str(domainsid), + "CONFIGDN": names.configdn, + "ADMINPASS_B64": b64encode(adminpass), + "KRBTGTPASS_B64": b64encode(krbtgtpass), + }) + + if serverrole == "domain controller": + message("Setting up self join") + setup_self_join(samdb, names=names, invocationid=invocationid, + dnspass=dnspass, + machinepass=machinepass, + domainsid=domainsid, policyguid=policyguid, + setup_path=setup_path) + + except: + samdb.transaction_cancel() + raise + + samdb.transaction_commit() + return samdb + + +FILL_FULL = "FULL" +FILL_NT4SYNC = "NT4SYNC" +FILL_DRS = "DRS" + +def provision(setup_dir, message, session_info, + credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, realm=None, + rootdn=None, domaindn=None, schemadn=None, configdn=None, + serverdn=None, + domain=None, hostname=None, hostip=None, hostip6=None, + domainsid=None, adminpass=None, krbtgtpass=None, domainguid=None, + policyguid=None, invocationid=None, machinepass=None, + dnspass=None, root=None, nobody=None, nogroup=None, users=None, + wheel=None, backup=None, aci=None, serverrole=None, + ldap_backend=None, ldap_backend_type=None, sitename=None): + """Provision samba4 + + :note: caution, this wipes all existing data! + """ + + def setup_path(file): + return os.path.join(setup_dir, file) + + if domainsid is None: + domainsid = security.random_sid() + else: + domainsid = security.Sid(domainsid) + + if policyguid is None: + policyguid = str(uuid.uuid4()) + if adminpass is None: + adminpass = misc.random_password(12) + if krbtgtpass is None: + krbtgtpass = misc.random_password(12) + if machinepass is None: + machinepass = misc.random_password(12) + if dnspass is None: + dnspass = misc.random_password(12) + root_uid = findnss_uid([root or "root"]) + nobody_uid = findnss_uid([nobody or "nobody"]) + users_gid = findnss_gid([users or "users"]) + if wheel is None: + wheel_gid = findnss_gid(["wheel", "adm"]) + else: + wheel_gid = findnss_gid([wheel]) + if aci is None: + aci = "# no aci for local ldb" + + if targetdir is not None: + if (not os.path.exists(os.path.join(targetdir, "etc"))): + os.makedirs(os.path.join(targetdir, "etc")) + smbconf = os.path.join(targetdir, "etc", "smb.conf") + + # only install a new smb.conf if there isn't one there already + if not os.path.exists(smbconf): + make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, + targetdir) + + lp = param.LoadParm() + lp.load(smbconf) + + names = guess_names(lp=lp, hostname=hostname, domain=domain, + dnsdomain=realm, serverrole=serverrole, sitename=sitename, + rootdn=rootdn, domaindn=domaindn, configdn=configdn, schemadn=schemadn, + serverdn=serverdn) + + paths = provision_paths_from_lp(lp, names.dnsdomain) + + if hostip is None: + hostip = socket.getaddrinfo(names.hostname, None, socket.AF_INET, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0] + + if hostip6 is None: + try: + hostip6 = socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0] + except socket.gaierror: + pass + + if serverrole is None: + serverrole = lp.get("server role") + + assert serverrole in ("domain controller", "member server", "standalone") + if invocationid is None and serverrole == "domain controller": + invocationid = str(uuid.uuid4()) + + if not os.path.exists(paths.private_dir): + os.mkdir(paths.private_dir) + + ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="") + + if ldap_backend is not None: + if ldap_backend == "ldapi": + # provision-backend will set this path suggested slapd command line / fedorads.inf + ldap_backend = "ldapi://%s" % urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") + + # only install a new shares config db if there is none + if not os.path.exists(paths.shareconf): + message("Setting up share.ldb") + share_ldb = Ldb(paths.shareconf, session_info=session_info, + credentials=credentials, lp=lp) + share_ldb.load_ldif_file_add(setup_path("share.ldif")) + + + message("Setting up secrets.ldb") + secrets_ldb = setup_secretsdb(paths.secrets, setup_path, + session_info=session_info, + credentials=credentials, lp=lp) + + message("Setting up the registry") + setup_registry(paths.hklm, setup_path, session_info, + credentials=credentials, lp=lp) + + message("Setting up templates db") + setup_templatesdb(paths.templates, setup_path, session_info=session_info, + credentials=credentials, lp=lp) + + message("Setting up idmap db") + idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info, + credentials=credentials, lp=lp) + + samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info, + credentials=credentials, lp=lp, names=names, + message=message, + domainsid=domainsid, + aci=aci, domainguid=domainguid, policyguid=policyguid, + fill=samdb_fill, + adminpass=adminpass, krbtgtpass=krbtgtpass, + invocationid=invocationid, + machinepass=machinepass, dnspass=dnspass, + serverrole=serverrole, ldap_backend=ldap_backend, + ldap_backend_type=ldap_backend_type) + + if lp.get("server role") == "domain controller": + if paths.netlogon is None: + message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.") + message("Please either remove %s or see the template at %s" % + ( paths.smbconf, setup_path("provision.smb.conf.dc"))) + assert(paths.netlogon is not None) + + if paths.sysvol is None: + message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.") + message("Please either remove %s or see the template at %s" % + (paths.smbconf, setup_path("provision.smb.conf.dc"))) + assert(paths.sysvol is not None) + + policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies", + "{" + policyguid + "}") + os.makedirs(policy_path, 0755) + open(os.path.join(policy_path, "GPT.INI"), 'w').write("") + os.makedirs(os.path.join(policy_path, "Machine"), 0755) + os.makedirs(os.path.join(policy_path, "User"), 0755) + if not os.path.isdir(paths.netlogon): + os.makedirs(paths.netlogon, 0755) + + if samdb_fill == FILL_FULL: + setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn, + root_uid=root_uid, nobody_uid=nobody_uid, + users_gid=users_gid, wheel_gid=wheel_gid) + + message("Setting up sam.ldb rootDSE marking as synchronized") + setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif")) + + # Only make a zone file on the first DC, it should be replicated with DNS replication + if serverrole == "domain controller": + secrets_ldb = Ldb(paths.secrets, session_info=session_info, + credentials=credentials, lp=lp) + secretsdb_become_dc(secrets_ldb, setup_path, domain=domain, realm=names.realm, + netbiosname=names.netbiosname, domainsid=domainsid, + keytab_path=paths.keytab, samdb_url=paths.samdb, + dns_keytab_path=paths.dns_keytab, dnspass=dnspass, + machinepass=machinepass, dnsdomain=names.dnsdomain) + + samdb = SamDB(paths.samdb, session_info=session_info, + credentials=credentials, lp=lp) + + domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID") + assert isinstance(domainguid, str) + hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID", + expression="(&(objectClass=computer)(cn=%s))" % names.hostname, + scope=SCOPE_SUBTREE) + assert isinstance(hostguid, str) + + create_zone_file(paths.dns, setup_path, dnsdomain=names.dnsdomain, + domaindn=names.domaindn, hostip=hostip, + hostip6=hostip6, hostname=names.hostname, + dnspass=dnspass, realm=names.realm, + domainguid=domainguid, hostguid=hostguid) + + create_named_conf(paths.namedconf, setup_path, realm=names.realm, + dnsdomain=names.dnsdomain, private_dir=paths.private_dir) + + create_named_txt(paths.namedtxt, setup_path, realm=names.realm, + dnsdomain=names.dnsdomain, private_dir=paths.private_dir, + keytab_name=paths.dns_keytab) + message("See %s for an example configuration include file for BIND" % paths.namedconf) + message("and %s for further documentation required for secure DNS updates" % paths.namedtxt) + + create_krb5_conf(paths.krb5conf, setup_path, dnsdomain=names.dnsdomain, + hostname=names.hostname, realm=names.realm) + message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf) + + create_phpldapadmin_config(paths.phpldapadminconfig, setup_path, + ldapi_url) + + message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig) + + message("Once the above files are installed, your Samba4 server will be ready to use") + message("Server Role: %s" % serverrole) + message("Hostname: %s" % names.hostname) + message("NetBIOS Domain: %s" % names.domain) + message("DNS Domain: %s" % names.dnsdomain) + message("DOMAIN SID: %s" % str(domainsid)) + message("Admin password: %s" % adminpass) + + result = ProvisionResult() + result.domaindn = domaindn + result.paths = paths + result.lp = lp + result.samdb = samdb + return result + + +def provision_become_dc(setup_dir=None, + smbconf=None, targetdir=None, realm=None, + rootdn=None, domaindn=None, schemadn=None, configdn=None, + serverdn=None, + domain=None, hostname=None, domainsid=None, + adminpass=None, krbtgtpass=None, domainguid=None, + policyguid=None, invocationid=None, machinepass=None, + dnspass=None, root=None, nobody=None, nogroup=None, users=None, + wheel=None, backup=None, aci=None, serverrole=None, + ldap_backend=None, ldap_backend_type=None, sitename=None): + + def message(text): + """print a message if quiet is not set.""" + print text + + return provision(setup_dir, message, system_session(), None, + smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS, realm=realm, + rootdn=rootdn, domaindn=domaindn, schemadn=schemadn, configdn=configdn, serverdn=serverdn, + domain=domain, hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename) + + +def setup_db_config(setup_path, dbdir): + """Setup a Berkeley database. + + :param setup_path: Setup path function. + :param dbdir: Database directory.""" + if not os.path.isdir(os.path.join(dbdir, "bdb-logs")): + os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700) + if not os.path.isdir(os.path.join(dbdir, "tmp")): + os.makedirs(os.path.join(dbdir, "tmp"), 0700) + + setup_file(setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"), + {"LDAPDBDIR": dbdir}) + + + +def provision_backend(setup_dir=None, message=None, + smbconf=None, targetdir=None, realm=None, + rootdn=None, domaindn=None, schemadn=None, configdn=None, + domain=None, hostname=None, adminpass=None, root=None, serverrole=None, + ldap_backend_type=None, ldap_backend_port=None, + ol_mmr_urls=None): + + def setup_path(file): + return os.path.join(setup_dir, file) + + if hostname is None: + hostname = socket.gethostname().split(".")[0].lower() + + if root is None: + root = findnss(pwd.getpwnam, ["root"])[0] + + if adminpass is None: + adminpass = misc.random_password(12) + + if targetdir is not None: + if (not os.path.exists(os.path.join(targetdir, "etc"))): + os.makedirs(os.path.join(targetdir, "etc")) + smbconf = os.path.join(targetdir, "etc", "smb.conf") + + # only install a new smb.conf if there isn't one there already + if not os.path.exists(smbconf): + make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, + targetdir) + + lp = param.LoadParm() + lp.load(smbconf) + + names = guess_names(lp=lp, hostname=hostname, domain=domain, + dnsdomain=realm, serverrole=serverrole, + rootdn=rootdn, domaindn=domaindn, configdn=configdn, + schemadn=schemadn) + + paths = provision_paths_from_lp(lp, names.dnsdomain) + + if not os.path.isdir(paths.ldapdir): + os.makedirs(paths.ldapdir, 0700) + schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb") + try: + os.unlink(schemadb_path) + except: + pass + + schemadb = Ldb(schemadb_path, lp=lp) + + prefixmap = open(setup_path("prefixMap.txt"), 'r').read() + + setup_add_ldif(schemadb, setup_path("provision_schema_basedn.ldif"), + {"SCHEMADN": names.schemadn, + "ACI": "#", + }) + setup_modify_ldif(schemadb, + setup_path("provision_schema_basedn_modify.ldif"), \ + {"SCHEMADN": names.schemadn, + "NETBIOSNAME": names.netbiosname, + "DEFAULTSITE": DEFAULTSITE, + "CONFIGDN": names.configdn, + "SERVERDN": names.serverdn, + "PREFIXMAP_B64": b64encode(prefixmap) + }) + + setup_add_ldif(schemadb, setup_path("schema_samba4.ldif"), + {"SCHEMADN": names.schemadn }) + setup_add_ldif(schemadb, setup_path("schema.ldif"), + {"SCHEMADN": names.schemadn}) + + if ldap_backend_type == "fedora-ds": + if ldap_backend_port is not None: + serverport = "ServerPort=%d" % ldap_backend_port + else: + serverport = "" + + setup_file(setup_path("fedorads.inf"), paths.fedoradsinf, + {"ROOT": root, + "HOSTNAME": hostname, + "DNSDOMAIN": names.dnsdomain, + "LDAPDIR": paths.ldapdir, + "DOMAINDN": names.domaindn, + "LDAPMANAGERDN": names.ldapmanagerdn, + "LDAPMANAGERPASS": adminpass, + "SERVERPORT": serverport}) + + setup_file(setup_path("fedorads-partitions.ldif"), paths.fedoradspartitions, + {"CONFIGDN": names.configdn, + "SCHEMADN": names.schemadn, + }) + + mapping = "schema-map-fedora-ds-1.0" + backend_schema = "99_ad.ldif" + + slapdcommand="Initailise Fedora DS with: setup-ds.pl --file=%s" % paths.fedoradsinf + + ldapuser = "--simple-bind-dn=" + names.ldapmanagerdn + + elif ldap_backend_type == "openldap": + attrs = ["linkID", "lDAPDisplayName"] + res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs) + + memberof_config = "# Generated from schema in %s\n" % schemadb_path + refint_attributes = "" + for i in range (0, len(res)): + expression = "(&(objectclass=attributeSchema)(linkID=%d))" % (int(res[i]["linkID"][0])+1) + target = schemadb.searchone(basedn=names.schemadn, + expression=expression, + attribute="lDAPDisplayName", + scope=SCOPE_SUBTREE) + if target is not None: + refint_attributes = refint_attributes + " " + target + " " + res[i]["lDAPDisplayName"][0] + + memberof_config += read_and_sub_file(setup_path("memberof.conf"), + { "MEMBER_ATTR" : str(res[i]["lDAPDisplayName"][0]), + "MEMBEROF_ATTR" : str(target) }) + + refint_config = read_and_sub_file(setup_path("refint.conf"), + { "LINK_ATTRS" : refint_attributes}) + +# generate serverids, ldap-urls and syncrepl-blocks for mmr hosts + mmr_on_config = "" + mmr_replicator_acl = "" + mmr_serverids_config = "" + mmr_syncrepl_schema_config = "" + mmr_syncrepl_config_config = "" + mmr_syncrepl_user_config = "" + + if ol_mmr_urls is not None: + # For now, make these equal + mmr_pass = adminpass + + url_list=filter(None,ol_mmr_urls.split(' ')) + if (len(url_list) == 1): + url_list=filter(None,ol_mmr_urls.split(',')) + + + mmr_on_config = "MirrorMode On" + mmr_replicator_acl = " by dn=cn=replicator,cn=samba read" + serverid=0 + for url in url_list: + serverid=serverid+1 + mmr_serverids_config += read_and_sub_file(setup_path("mmr_serverids.conf"), + { "SERVERID" : str(serverid), + "LDAPSERVER" : url }) + rid=serverid*10 + rid=rid+1 + mmr_syncrepl_schema_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"), + { "RID" : str(rid), + "MMRDN": names.schemadn, + "LDAPSERVER" : url, + "MMR_PASSWORD": mmr_pass}) + + rid=rid+1 + mmr_syncrepl_config_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"), + { "RID" : str(rid), + "MMRDN": names.configdn, + "LDAPSERVER" : url, + "MMR_PASSWORD": mmr_pass}) + + rid=rid+1 + mmr_syncrepl_user_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"), + { "RID" : str(rid), + "MMRDN": names.domaindn, + "LDAPSERVER" : url, + "MMR_PASSWORD": mmr_pass }) + + + setup_file(setup_path("slapd.conf"), paths.slapdconf, + {"DNSDOMAIN": names.dnsdomain, + "LDAPDIR": paths.ldapdir, + "DOMAINDN": names.domaindn, + "CONFIGDN": names.configdn, + "SCHEMADN": names.schemadn, + "MEMBEROF_CONFIG": memberof_config, + "MIRRORMODE": mmr_on_config, + "REPLICATOR_ACL": mmr_replicator_acl, + "MMR_SERVERIDS_CONFIG": mmr_serverids_config, + "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config, + "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config, + "MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config, + "REFINT_CONFIG": refint_config}) + setup_file(setup_path("modules.conf"), paths.modulesconf, + {"REALM": names.realm}) + + setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "user")) + setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "config")) + setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "schema")) + + if not os.path.exists(os.path.join(paths.ldapdir, "db", "samba", "cn=samba")): + os.makedirs(os.path.join(paths.ldapdir, "db", "samba", "cn=samba"), 0700) + + setup_file(setup_path("cn=samba.ldif"), + os.path.join(paths.ldapdir, "db", "samba", "cn=samba.ldif"), + { "UUID": str(uuid.uuid4()), + "LDAPTIME": timestring(int(time.time()))} ) + setup_file(setup_path("cn=samba-admin.ldif"), + os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=samba-admin.ldif"), + {"LDAPADMINPASS_B64": b64encode(adminpass), + "UUID": str(uuid.uuid4()), + "LDAPTIME": timestring(int(time.time()))} ) + + if ol_mmr_urls is not None: + setup_file(setup_path("cn=replicator.ldif"), + os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=replicator.ldif"), + {"MMR_PASSWORD_B64": b64encode(mmr_pass), + "UUID": str(uuid.uuid4()), + "LDAPTIME": timestring(int(time.time()))} ) + + + + mapping = "schema-map-openldap-2.3" + backend_schema = "backend-schema.schema" + + ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") + if ldap_backend_port is not None: + server_port_string = " -h ldap://0.0.0.0:%d" % ldap_backend_port + else: + server_port_string = "" + + slapdcommand="Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string + + ldapuser = "--username=samba-admin" + + + schema_command = "bin/ad2oLschema --option=convert:target=" + ldap_backend_type + " -I " + setup_path(mapping) + " -H tdb://" + schemadb_path + " -O " + os.path.join(paths.ldapdir, backend_schema) + + os.system(schema_command) + + message("Your %s Backend for Samba4 is now configured, and is ready to be started" % ldap_backend_type) + message("Server Role: %s" % serverrole) + message("Hostname: %s" % names.hostname) + message("DNS Domain: %s" % names.dnsdomain) + message("Base DN: %s" % names.domaindn) + + if ldap_backend_type == "openldap": + message("LDAP admin user: samba-admin") + else: + message("LDAP admin DN: %s" % names.ldapmanagerdn) + + message("LDAP admin password: %s" % adminpass) + message(slapdcommand) + message("Run provision with: --ldap-backend=ldapi --ldap-backend-type=" + ldap_backend_type + " --password=" + adminpass + " " + ldapuser) + +def create_phpldapadmin_config(path, setup_path, ldapi_uri): + """Create a PHP LDAP admin configuration file. + + :param path: Path to write the configuration to. + :param setup_path: Function to generate setup paths. + """ + setup_file(setup_path("phpldapadmin-config.php"), path, + {"S4_LDAPI_URI": ldapi_uri}) + + +def create_zone_file(path, setup_path, dnsdomain, domaindn, + hostip, hostip6, hostname, dnspass, realm, domainguid, hostguid): + """Write out a DNS zone file, from the info in the current database. + + :param path: Path of the new zone file. + :param setup_path: Setup path function. + :param dnsdomain: DNS Domain name + :param domaindn: DN of the Domain + :param hostip: Local IPv4 IP + :param hostip6: Local IPv6 IP + :param hostname: Local hostname + :param dnspass: Password for DNS + :param realm: Realm name + :param domainguid: GUID of the domain. + :param hostguid: GUID of the host. + """ + assert isinstance(domainguid, str) + + if hostip6 is not None: + hostip6_base_line = " IN AAAA " + hostip6 + hostip6_host_line = hostname + " IN AAAA " + hostip6 + else: + hostip6_base_line = "" + hostip6_host_line = "" + + setup_file(setup_path("provision.zone"), path, { + "DNSPASS_B64": b64encode(dnspass), + "HOSTNAME": hostname, + "DNSDOMAIN": dnsdomain, + "REALM": realm, + "HOSTIP": hostip, + "DOMAINGUID": domainguid, + "DATESTRING": time.strftime("%Y%m%d%H"), + "DEFAULTSITE": DEFAULTSITE, + "HOSTGUID": hostguid, + "HOSTIP6_BASE_LINE": hostip6_base_line, + "HOSTIP6_HOST_LINE": hostip6_host_line, + }) + + +def create_named_conf(path, setup_path, realm, dnsdomain, + private_dir): + """Write out a file containing zone statements suitable for inclusion in a + named.conf file (including GSS-TSIG configuration). + + :param path: Path of the new named.conf file. + :param setup_path: Setup path function. + :param realm: Realm name + :param dnsdomain: DNS Domain name + :param private_dir: Path to private directory + :param keytab_name: File name of DNS keytab file + """ + + setup_file(setup_path("named.conf"), path, { + "DNSDOMAIN": dnsdomain, + "REALM": realm, + "REALM_WC": "*." + ".".join(realm.split(".")[1:]), + "PRIVATE_DIR": private_dir + }) + +def create_named_txt(path, setup_path, realm, dnsdomain, + private_dir, keytab_name): + """Write out a file containing zone statements suitable for inclusion in a + named.conf file (including GSS-TSIG configuration). + + :param path: Path of the new named.conf file. + :param setup_path: Setup path function. + :param realm: Realm name + :param dnsdomain: DNS Domain name + :param private_dir: Path to private directory + :param keytab_name: File name of DNS keytab file + """ + + setup_file(setup_path("named.txt"), path, { + "DNSDOMAIN": dnsdomain, + "REALM": realm, + "DNS_KEYTAB": keytab_name, + "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name), + "PRIVATE_DIR": private_dir + }) + +def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm): + """Write out a file containing zone statements suitable for inclusion in a + named.conf file (including GSS-TSIG configuration). + + :param path: Path of the new named.conf file. + :param setup_path: Setup path function. + :param dnsdomain: DNS Domain name + :param hostname: Local hostname + :param realm: Realm name + """ + + setup_file(setup_path("krb5.conf"), path, { + "DNSDOMAIN": dnsdomain, + "HOSTNAME": hostname, + "REALM": realm, + }) + + +def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename, + serverdn, servername): + """Load schema for the SamDB. + + :param samdb: Load a schema into a SamDB. + :param setup_path: Setup path function. + :param schemadn: DN of the schema + :param netbiosname: NetBIOS name of the host. + :param configdn: DN of the configuration + :param serverdn: DN of the server + :param servername: Host name of the server + """ + schema_data = open(setup_path("schema.ldif"), 'r').read() + schema_data += open(setup_path("schema_samba4.ldif"), 'r').read() + schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn}) + check_all_substituted(schema_data) + prefixmap = open(setup_path("prefixMap.txt"), 'r').read() + prefixmap = b64encode(prefixmap) + + head_data = open(setup_path("provision_schema_basedn_modify.ldif"), 'r').read() + head_data = substitute_var(head_data, { + "SCHEMADN": schemadn, + "NETBIOSNAME": netbiosname, + "CONFIGDN": configdn, + "DEFAULTSITE": sitename, + "PREFIXMAP_B64": prefixmap, + "SERVERDN": serverdn, + "SERVERNAME": servername, + }) + check_all_substituted(head_data) + samdb.attach_schema_from_ldif(head_data, schema_data) + diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py new file mode 100644 index 0000000000..0e0c29dac8 --- /dev/null +++ b/source4/scripting/python/samba/samba3.py @@ -0,0 +1,711 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# 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/>. +# + +"""Support for reading Samba 3 data files.""" + +__docformat__ = "restructuredText" + +REGISTRY_VALUE_PREFIX = "SAMBA_REGVAL" +REGISTRY_DB_VERSION = 1 + +import os +import tdb + + +class TdbDatabase(object): + """Simple Samba 3 TDB database reader.""" + def __init__(self, file): + """Open a file. + + :param file: Path of the file to open. + """ + self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) + self._check_version() + + def _check_version(self): + pass + + def close(self): + """Close resources associated with this object.""" + self.tdb.close() + + +class Registry(TdbDatabase): + """Simple read-only support for reading the Samba3 registry. + + :note: This object uses the same syntax for registry key paths as + Samba 3. This particular format uses forward slashes for key path + separators and abbreviations for the predefined key names. + e.g.: HKLM/Software/Bar. + """ + def __len__(self): + """Return the number of keys.""" + return len(self.keys()) + + def keys(self): + """Return list with all the keys.""" + return [k.rstrip("\x00") for k in self.tdb.keys() if not k.startswith(REGISTRY_VALUE_PREFIX)] + + def subkeys(self, key): + """Retrieve the subkeys for the specified key. + + :param key: Key path. + :return: list with key names + """ + data = self.tdb.get("%s\x00" % key) + if data is None: + return [] + import struct + (num, ) = struct.unpack("<L", data[0:4]) + keys = data[4:].split("\0") + assert keys[-1] == "" + keys.pop() + assert len(keys) == num + return keys + + def values(self, key): + """Return a dictionary with the values set for a specific key. + + :param key: Key to retrieve values for. + :return: Dictionary with value names as key, tuple with type and + data as value.""" + data = self.tdb.get("%s/%s\x00" % (REGISTRY_VALUE_PREFIX, key)) + if data is None: + return {} + ret = {} + import struct + (num, ) = struct.unpack("<L", data[0:4]) + data = data[4:] + for i in range(num): + # Value name + (name, data) = data.split("\0", 1) + + (type, ) = struct.unpack("<L", data[0:4]) + data = data[4:] + (value_len, ) = struct.unpack("<L", data[0:4]) + data = data[4:] + + ret[name] = (type, data[:value_len]) + data = data[value_len:] + + return ret + + +class PolicyDatabase(TdbDatabase): + """Samba 3 Account Policy database reader.""" + def __init__(self, file): + """Open a policy database + + :param file: Path to the file to open. + """ + super(PolicyDatabase, self).__init__(file) + self.min_password_length = self.tdb.fetch_uint32("min password length\x00") + self.password_history = self.tdb.fetch_uint32("password history\x00") + self.user_must_logon_to_change_password = self.tdb.fetch_uint32("user must logon to change pasword\x00") + self.maximum_password_age = self.tdb.fetch_uint32("maximum password age\x00") + self.minimum_password_age = self.tdb.fetch_uint32("minimum password age\x00") + self.lockout_duration = self.tdb.fetch_uint32("lockout duration\x00") + self.reset_count_minutes = self.tdb.fetch_uint32("reset count minutes\x00") + self.bad_lockout_minutes = self.tdb.fetch_uint32("bad lockout minutes\x00") + self.disconnect_time = self.tdb.fetch_int32("disconnect time\x00") + self.refuse_machine_password_change = self.tdb.fetch_uint32("refuse machine password change\x00") + + # FIXME: Read privileges as well + + +GROUPDB_DATABASE_VERSION_V1 = 1 # native byte format. +GROUPDB_DATABASE_VERSION_V2 = 2 # le format. + +GROUP_PREFIX = "UNIXGROUP/" + +# Alias memberships are stored reverse, as memberships. The performance +# critical operation is to determine the aliases a SID is member of, not +# listing alias members. So we store a list of alias SIDs a SID is member of +# hanging of the member as key. +MEMBEROF_PREFIX = "MEMBEROF/" + +class GroupMappingDatabase(TdbDatabase): + """Samba 3 group mapping database reader.""" + def _check_version(self): + assert self.tdb.fetch_int32("INFO/version\x00") in (GROUPDB_DATABASE_VERSION_V1, GROUPDB_DATABASE_VERSION_V2) + + def groupsids(self): + """Retrieve the SIDs for the groups in this database. + + :return: List with sids as strings. + """ + for k in self.tdb.keys(): + if k.startswith(GROUP_PREFIX): + yield k[len(GROUP_PREFIX):].rstrip("\0") + + def get_group(self, sid): + """Retrieve the group mapping information for a particular group. + + :param sid: SID of the group + :return: None if the group can not be found, otherwise + a tuple with gid, sid_name_use, the NT name and comment. + """ + data = self.tdb.get("%s%s\0" % (GROUP_PREFIX, sid)) + if data is None: + return data + import struct + (gid, sid_name_use) = struct.unpack("<lL", data[0:8]) + (nt_name, comment, _) = data[8:].split("\0") + return (gid, sid_name_use, nt_name, comment) + + def aliases(self): + """Retrieve the aliases in this database.""" + for k in self.tdb.keys(): + if k.startswith(MEMBEROF_PREFIX): + yield k[len(MEMBEROF_PREFIX):].rstrip("\0") + + +# High water mark keys +IDMAP_HWM_GROUP = "GROUP HWM\0" +IDMAP_HWM_USER = "USER HWM\0" + +IDMAP_GROUP_PREFIX = "GID " +IDMAP_USER_PREFIX = "UID " + +# idmap version determines auto-conversion +IDMAP_VERSION_V2 = 2 + +class IdmapDatabase(TdbDatabase): + """Samba 3 ID map database reader.""" + def _check_version(self): + assert self.tdb.fetch_int32("IDMAP_VERSION\0") == IDMAP_VERSION_V2 + + def uids(self): + """Retrieve a list of all uids in this database.""" + for k in self.tdb.keys(): + if k.startswith(IDMAP_USER_PREFIX): + yield int(k[len(IDMAP_USER_PREFIX):].rstrip("\0")) + + def gids(self): + """Retrieve a list of all gids in this database.""" + for k in self.tdb.keys(): + if k.startswith(IDMAP_GROUP_PREFIX): + yield int(k[len(IDMAP_GROUP_PREFIX):].rstrip("\0")) + + def get_user_sid(self, uid): + """Retrieve the SID associated with a particular uid. + + :param uid: UID to retrieve SID for. + :return: A SID or None if no mapping was found. + """ + data = self.tdb.get("%s%d\0" % (IDMAP_USER_PREFIX, uid)) + if data is None: + return data + return data.rstrip("\0") + + def get_group_sid(self, gid): + data = self.tdb.get("%s%d\0" % (IDMAP_GROUP_PREFIX, gid)) + if data is None: + return data + return data.rstrip("\0") + + def get_user_hwm(self): + """Obtain the user high-water mark.""" + return self.tdb.fetch_uint32(IDMAP_HWM_USER) + + def get_group_hwm(self): + """Obtain the group high-water mark.""" + return self.tdb.fetch_uint32(IDMAP_HWM_GROUP) + + +class SecretsDatabase(TdbDatabase): + """Samba 3 Secrets database reader.""" + def get_auth_password(self): + return self.tdb.get("SECRETS/AUTH_PASSWORD") + + def get_auth_domain(self): + return self.tdb.get("SECRETS/AUTH_DOMAIN") + + def get_auth_user(self): + return self.tdb.get("SECRETS/AUTH_USER") + + def get_domain_guid(self, host): + return self.tdb.get("SECRETS/DOMGUID/%s" % host) + + def ldap_dns(self): + for k in self.tdb.keys(): + if k.startswith("SECRETS/LDAP_BIND_PW/"): + yield k[len("SECRETS/LDAP_BIND_PW/"):].rstrip("\0") + + def domains(self): + """Iterate over domains in this database. + + :return: Iterator over the names of domains in this database. + """ + for k in self.tdb.keys(): + if k.startswith("SECRETS/SID/"): + yield k[len("SECRETS/SID/"):].rstrip("\0") + + def get_ldap_bind_pw(self, host): + return self.tdb.get("SECRETS/LDAP_BIND_PW/%s" % host) + + def get_afs_keyfile(self, host): + return self.tdb.get("SECRETS/AFS_KEYFILE/%s" % host) + + def get_machine_sec_channel_type(self, host): + return self.tdb.fetch_uint32("SECRETS/MACHINE_SEC_CHANNEL_TYPE/%s" % host) + + def get_machine_last_change_time(self, host): + return self.tdb.fetch_uint32("SECRETS/MACHINE_LAST_CHANGE_TIME/%s" % host) + + def get_machine_password(self, host): + return self.tdb.get("SECRETS/MACHINE_PASSWORD/%s" % host) + + def get_machine_acc(self, host): + return self.tdb.get("SECRETS/$MACHINE.ACC/%s" % host) + + def get_domtrust_acc(self, host): + return self.tdb.get("SECRETS/$DOMTRUST.ACC/%s" % host) + + def trusted_domains(self): + for k in self.tdb.keys(): + if k.startswith("SECRETS/$DOMTRUST.ACC/"): + yield k[len("SECRETS/$DOMTRUST.ACC/"):].rstrip("\0") + + def get_random_seed(self): + return self.tdb.get("INFO/random_seed") + + def get_sid(self, host): + return self.tdb.get("SECRETS/SID/%s" % host.upper()) + + +SHARE_DATABASE_VERSION_V1 = 1 +SHARE_DATABASE_VERSION_V2 = 2 + +class ShareInfoDatabase(TdbDatabase): + """Samba 3 Share Info database reader.""" + def _check_version(self): + assert self.tdb.fetch_int32("INFO/version\0") in (SHARE_DATABASE_VERSION_V1, SHARE_DATABASE_VERSION_V2) + + def get_secdesc(self, name): + """Obtain the security descriptor on a particular share. + + :param name: Name of the share + """ + secdesc = self.tdb.get("SECDESC/%s" % name) + # FIXME: Run ndr_pull_security_descriptor + return secdesc + + +class Shares(object): + """Container for share objects.""" + def __init__(self, lp, shareinfo): + self.lp = lp + self.shareinfo = shareinfo + + def __len__(self): + """Number of shares.""" + return len(self.lp) - 1 + + def __iter__(self): + """Iterate over the share names.""" + return self.lp.__iter__() + + +ACB_DISABLED = 0x00000001 +ACB_HOMDIRREQ = 0x00000002 +ACB_PWNOTREQ = 0x00000004 +ACB_TEMPDUP = 0x00000008 +ACB_NORMAL = 0x00000010 +ACB_MNS = 0x00000020 +ACB_DOMTRUST = 0x00000040 +ACB_WSTRUST = 0x00000080 +ACB_SVRTRUST = 0x00000100 +ACB_PWNOEXP = 0x00000200 +ACB_AUTOLOCK = 0x00000400 +ACB_ENC_TXT_PWD_ALLOWED = 0x00000800 +ACB_SMARTCARD_REQUIRED = 0x00001000 +ACB_TRUSTED_FOR_DELEGATION = 0x00002000 +ACB_NOT_DELEGATED = 0x00004000 +ACB_USE_DES_KEY_ONLY = 0x00008000 +ACB_DONT_REQUIRE_PREAUTH = 0x00010000 +ACB_PW_EXPIRED = 0x00020000 +ACB_NO_AUTH_DATA_REQD = 0x00080000 + +acb_info_mapping = { + 'N': ACB_PWNOTREQ, # 'N'o password. + 'D': ACB_DISABLED, # 'D'isabled. + 'H': ACB_HOMDIRREQ, # 'H'omedir required. + 'T': ACB_TEMPDUP, # 'T'emp account. + 'U': ACB_NORMAL, # 'U'ser account (normal). + 'M': ACB_MNS, # 'M'NS logon user account. What is this ? + 'W': ACB_WSTRUST, # 'W'orkstation account. + 'S': ACB_SVRTRUST, # 'S'erver account. + 'L': ACB_AUTOLOCK, # 'L'ocked account. + 'X': ACB_PWNOEXP, # No 'X'piry on password + 'I': ACB_DOMTRUST, # 'I'nterdomain trust account. + ' ': 0 + } + +def decode_acb(text): + """Decode a ACB field. + + :param text: ACB text + :return: integer with flags set. + """ + assert not "[" in text and not "]" in text + ret = 0 + for x in text: + ret |= acb_info_mapping[x] + return ret + + +class SAMUser(object): + """Samba 3 SAM User. + + :note: Unknown or unset fields are set to None. + """ + def __init__(self, name, uid=None, lm_password=None, nt_password=None, acct_ctrl=None, + last_change_time=None, nt_username=None, fullname=None, logon_time=None, logoff_time=None, + acct_desc=None, group_rid=None, bad_password_count=None, logon_count=None, + domain=None, dir_drive=None, munged_dial=None, homedir=None, logon_script=None, + profile_path=None, workstations=None, kickoff_time=None, bad_password_time=None, + pass_last_set_time=None, pass_can_change_time=None, pass_must_change_time=None, + user_rid=None, unknown_6=None, nt_password_history=None, + unknown_str=None, hours=None, logon_divs=None): + self.username = name + self.uid = uid + self.lm_password = lm_password + self.nt_password = nt_password + self.acct_ctrl = acct_ctrl + self.pass_last_set_time = last_change_time + self.nt_username = nt_username + self.fullname = fullname + self.logon_time = logon_time + self.logoff_time = logoff_time + self.acct_desc = acct_desc + self.group_rid = group_rid + self.bad_password_count = bad_password_count + self.logon_count = logon_count + self.domain = domain + self.dir_drive = dir_drive + self.munged_dial = munged_dial + self.homedir = homedir + self.logon_script = logon_script + self.profile_path = profile_path + self.workstations = workstations + self.kickoff_time = kickoff_time + self.bad_password_time = bad_password_time + self.pass_can_change_time = pass_can_change_time + self.pass_must_change_time = pass_must_change_time + self.user_rid = user_rid + self.unknown_6 = unknown_6 + self.nt_password_history = nt_password_history + self.unknown_str = unknown_str + self.hours = hours + self.logon_divs = logon_divs + + def __eq__(self, other): + if not isinstance(other, SAMUser): + return False + return self.__dict__ == other.__dict__ + + +class SmbpasswdFile(object): + """Samba 3 smbpasswd file reader.""" + def __init__(self, file): + self.users = {} + f = open(file, 'r') + for l in f.readlines(): + if len(l) == 0 or l[0] == "#": + continue # Skip comments and blank lines + parts = l.split(":") + username = parts[0] + uid = int(parts[1]) + acct_ctrl = 0 + last_change_time = None + if parts[2] == "NO PASSWORD": + acct_ctrl |= ACB_PWNOTREQ + lm_password = None + elif parts[2][0] in ("*", "X"): + # No password set + lm_password = None + else: + lm_password = parts[2] + + if parts[3][0] in ("*", "X"): + # No password set + nt_password = None + else: + nt_password = parts[3] + + if parts[4][0] == '[': + assert "]" in parts[4] + acct_ctrl |= decode_acb(parts[4][1:-1]) + if parts[5].startswith("LCT-"): + last_change_time = int(parts[5][len("LCT-"):], 16) + else: # old style file + if username[-1] == "$": + acct_ctrl &= ~ACB_NORMAL + acct_ctrl |= ACB_WSTRUST + + self.users[username] = SAMUser(username, uid, lm_password, nt_password, acct_ctrl, last_change_time) + + f.close() + + def __len__(self): + return len(self.users) + + def __getitem__(self, name): + return self.users[name] + + def __iter__(self): + return iter(self.users) + + def close(self): # For consistency + pass + + +TDBSAM_FORMAT_STRING_V0 = "ddddddBBBBBBBBBBBBddBBwdwdBwwd" +TDBSAM_FORMAT_STRING_V1 = "dddddddBBBBBBBBBBBBddBBwdwdBwwd" +TDBSAM_FORMAT_STRING_V2 = "dddddddBBBBBBBBBBBBddBBBwwdBwwd" +TDBSAM_USER_PREFIX = "USER_" + + +class LdapSam(object): + """Samba 3 LDAP passdb backend reader.""" + def __init__(self, url): + self.ldap_url = ldap_url + + +class TdbSam(TdbDatabase): + """Samba 3 TDB passdb backend reader.""" + def _check_version(self): + self.version = self.tdb.fetch_uint32("INFO/version\0") or 0 + assert self.version in (0, 1, 2) + + def usernames(self): + """Iterate over the usernames in this Tdb database.""" + for k in self.tdb.keys(): + if k.startswith(TDBSAM_USER_PREFIX): + yield k[len(TDBSAM_USER_PREFIX):].rstrip("\0") + + __iter__ = usernames + + def __getitem__(self, name): + data = self.tdb["%s%s\0" % (TDBSAM_USER_PREFIX, name)] + user = SAMUser(name) + import struct + + def unpack_string(data): + (length, ) = struct.unpack("<L", data[:4]) + data = data[4:] + if length == 0: + return (None, data) + return (data[:length].rstrip("\0"), data[length:]) + + def unpack_int32(data): + (value, ) = struct.unpack("<l", data[:4]) + return (value, data[4:]) + + def unpack_uint32(data): + (value, ) = struct.unpack("<L", data[:4]) + return (value, data[4:]) + + def unpack_uint16(data): + (value, ) = struct.unpack("<H", data[:2]) + return (value, data[2:]) + + (logon_time, data) = unpack_int32(data) + (logoff_time, data) = unpack_int32(data) + (kickoff_time, data) = unpack_int32(data) + + if self.version > 0: + (bad_password_time, data) = unpack_int32(data) + if bad_password_time != 0: + user.bad_password_time = bad_password_time + (pass_last_set_time, data) = unpack_int32(data) + (pass_can_change_time, data) = unpack_int32(data) + (pass_must_change_time, data) = unpack_int32(data) + + if logon_time != 0: + user.logon_time = logon_time + user.logoff_time = logoff_time + user.kickoff_time = kickoff_time + if pass_last_set_time != 0: + user.pass_last_set_time = pass_last_set_time + user.pass_can_change_time = pass_can_change_time + + (user.username, data) = unpack_string(data) + (user.domain, data) = unpack_string(data) + (user.nt_username, data) = unpack_string(data) + (user.fullname, data) = unpack_string(data) + (user.homedir, data) = unpack_string(data) + (user.dir_drive, data) = unpack_string(data) + (user.logon_script, data) = unpack_string(data) + (user.profile_path, data) = unpack_string(data) + (user.acct_desc, data) = unpack_string(data) + (user.workstations, data) = unpack_string(data) + (user.unknown_str, data) = unpack_string(data) + (user.munged_dial, data) = unpack_string(data) + + (user.user_rid, data) = unpack_int32(data) + (user.group_rid, data) = unpack_int32(data) + + (user.lm_password, data) = unpack_string(data) + (user.nt_password, data) = unpack_string(data) + + if self.version > 1: + (user.nt_password_history, data) = unpack_string(data) + + (user.acct_ctrl, data) = unpack_uint16(data) + (_, data) = unpack_uint32(data) # remove_me field + (user.logon_divs, data) = unpack_uint16(data) + (hours, data) = unpack_string(data) + user.hours = [] + for entry in hours: + for i in range(8): + user.hours.append(ord(entry) & (2 ** i) == (2 ** i)) + (user.bad_password_count, data) = unpack_uint16(data) + (user.logon_count, data) = unpack_uint16(data) + (user.unknown_6, data) = unpack_uint32(data) + assert len(data) == 0 + return user + + +def shellsplit(text): + """Very simple shell-like line splitting. + + :param text: Text to split. + :return: List with parts of the line as strings. + """ + ret = list() + inquotes = False + current = "" + for c in text: + if c == "\"": + inquotes = not inquotes + elif c in ("\t", "\n", " ") and not inquotes: + ret.append(current) + current = "" + else: + current += c + if current != "": + ret.append(current) + return ret + + +class WinsDatabase(object): + """Samba 3 WINS database reader.""" + def __init__(self, file): + self.entries = {} + f = open(file, 'r') + assert f.readline().rstrip("\n") == "VERSION 1 0" + for l in f.readlines(): + if l[0] == "#": # skip comments + continue + entries = shellsplit(l.rstrip("\n")) + name = entries[0] + ttl = int(entries[1]) + i = 2 + ips = [] + while "." in entries[i]: + ips.append(entries[i]) + i+=1 + nb_flags = int(entries[i][:-1], 16) + assert not name in self.entries, "Name %s exists twice" % name + self.entries[name] = (ttl, ips, nb_flags) + f.close() + + def __getitem__(self, name): + return self.entries[name] + + def __len__(self): + return len(self.entries) + + def __iter__(self): + return iter(self.entries) + + def items(self): + """Return the entries in this WINS database.""" + return self.entries.items() + + def close(self): # for consistency + pass + + +class Samba3(object): + """Samba 3 configuration and state data reader.""" + def __init__(self, libdir, smbconfpath): + """Open the configuration and data for a Samba 3 installation. + + :param libdir: Library directory + :param smbconfpath: Path to the smb.conf file. + """ + self.smbconfpath = smbconfpath + self.libdir = libdir + import param + self.lp = param.ParamFile() + self.lp.read(self.smbconfpath) + + def libdir_path(self, path): + if path[0] == "/" or path[0] == ".": + return path + return os.path.join(self.libdir, path) + + def get_conf(self): + return self.lp + + def get_sam_db(self): + lp = self.get_conf() + backends = str(lp.get("passdb backend")).split(" ") + if ":" in backends[0]: + (name, location) = backends[0].split(":", 2) + else: + name = backends[0] + location = None + if name == "smbpasswd": + return SmbpasswdFile(self.libdir_path(location or "smbpasswd")) + elif name == "tdbsam": + return TdbSam(self.libdir_path(location or "passdb.tdb")) + elif name == "ldapsam": + if location is not None: + return LdapSam("ldap:%s" % location) + return LdapSam(lp.get("ldap server")) + else: + raise NotImplementedError("unsupported passdb backend %s" % backends[0]) + + def get_policy_db(self): + return PolicyDatabase(self.libdir_path("account_policy.tdb")) + + def get_registry(self): + return Registry(self.libdir_path("registry.tdb")) + + def get_secrets_db(self): + return SecretsDatabase(self.libdir_path("secrets.tdb")) + + def get_shareinfo_db(self): + return ShareInfoDatabase(self.libdir_path("share_info.tdb")) + + def get_idmap_db(self): + return IdmapDatabase(self.libdir_path("winbindd_idmap.tdb")) + + def get_wins_db(self): + return WinsDatabase(self.libdir_path("wins.dat")) + + def get_shares(self): + return Shares(self.get_conf(), self.get_shareinfo_db()) + + def get_groupmapping_db(self): + return GroupMappingDatabase(self.libdir_path("group_mapping.tdb")) diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py new file mode 100644 index 0000000000..4a64c2f76d --- /dev/null +++ b/source4/scripting/python/samba/samdb.py @@ -0,0 +1,227 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008 +# +# Based on the original in EJS: +# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005 +# +# 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/>. +# + +"""Convenience functions for using the SAM.""" + +import samba +import misc +import ldb +from samba.idmap import IDmapDB +import pwd +import time + +__docformat__ = "restructuredText" + +class SamDB(samba.Ldb): + """The SAM database.""" + + def __init__(self, url=None, session_info=None, credentials=None, + modules_dir=None, lp=None): + """Open the Sam Database. + + :param url: URL of the database. + """ + self.lp = lp + super(SamDB, self).__init__(session_info=session_info, credentials=credentials, + modules_dir=modules_dir, lp=lp) + assert misc.dsdb_set_global_schema(self) == 0 + if url: + self.connect(url) + else: + self.connect(lp.get("sam database")) + + def connect(self, url): + super(SamDB, self).connect(misc.private_path(self.lp, url)) + + def add_foreign(self, domaindn, sid, desc): + """Add a foreign security principle.""" + add = """ +dn: CN=%s,CN=ForeignSecurityPrincipals,%s +objectClass: top +objectClass: foreignSecurityPrincipal +description: %s + """ % (sid, domaindn, desc) + # deliberately ignore errors from this, as the records may + # already exist + for msg in self.parse_ldif(add): + self.add(msg[1]) + + def enable_account(self, user_dn): + """Enable an account. + + :param user_dn: Dn of the account to enable. + """ + res = self.search(user_dn, ldb.SCOPE_BASE, None, ["userAccountControl"]) + assert len(res) == 1 + userAccountControl = res[0]["userAccountControl"][0] + userAccountControl = int(userAccountControl) + if (userAccountControl & 0x2): + userAccountControl = userAccountControl & ~0x2 # remove disabled bit + if (userAccountControl & 0x20): + userAccountControl = userAccountControl & ~0x20 # remove 'no password required' bit + + mod = """ +dn: %s +changetype: modify +replace: userAccountControl +userAccountControl: %u +""" % (user_dn, userAccountControl) + self.modify_ldif(mod) + + def domain_dn(self): + # find the DNs for the domain and the domain users group + res = self.search("", scope=ldb.SCOPE_BASE, + expression="(defaultNamingContext=*)", + attrs=["defaultNamingContext"]) + assert(len(res) == 1 and res[0]["defaultNamingContext"] is not None) + return res[0]["defaultNamingContext"][0] + + def newuser(self, username, unixname, password): + """add a new user record. + + :param username: Name of the new user. + :param unixname: Name of the unix user to map to. + :param password: Password for the new user + """ + # connect to the sam + self.transaction_start() + + domain_dn = self.domain_dn() + assert(domain_dn is not None) + user_dn = "CN=%s,CN=Users,%s" % (username, domain_dn) + + # + # the new user record. note the reliance on the samdb module to fill + # in a sid, guid etc + # + # now the real work + self.add({"dn": user_dn, + "sAMAccountName": username, + "userPassword": password, + "objectClass": "user"}) + + res = self.search(user_dn, scope=ldb.SCOPE_BASE, + expression="objectclass=*", + attrs=["objectSid"]) + assert(len(res) == 1) + user_sid = self.schema_format_value("objectSid", res[0]["objectSid"][0]) + + + try: + idmap = IDmapDB(lp=self.lp) + + user = pwd.getpwnam(unixname) + # setup ID mapping for this UID + + idmap.setup_name_mapping(user_sid, idmap.TYPE_UID, user[2]) + + except KeyError: + pass + + # modify the userAccountControl to remove the disabled bit + self.enable_account(user_dn) + self.transaction_commit() + + def setpassword(self, filter, password): + """Set a password on a user record + + :param filter: LDAP filter to find the user (eg samccountname=name) + :param password: Password for the user + """ + # connect to the sam + self.transaction_start() + + # find the DNs for the domain + res = self.search("", scope=ldb.SCOPE_BASE, + expression="(defaultNamingContext=*)", + attrs=["defaultNamingContext"]) + assert(len(res) == 1 and res[0]["defaultNamingContext"] is not None) + domain_dn = res[0]["defaultNamingContext"][0] + assert(domain_dn is not None) + + res = self.search(domain_dn, scope=ldb.SCOPE_SUBTREE, + expression=filter, + attrs=[]) + assert(len(res) == 1) + user_dn = res[0].dn + + setpw = """ +dn: %s +changetype: modify +replace: userPassword +userPassword: %s +""" % (user_dn, password) + + self.modify_ldif(setpw) + + # modify the userAccountControl to remove the disabled bit + self.enable_account(user_dn) + self.transaction_commit() + + def set_domain_sid(self, sid): + """Change the domain SID used by this SamDB. + + :param sid: The new domain sid to use. + """ + misc.samdb_set_domain_sid(self, sid) + + def attach_schema_from_ldif(self, pf, df): + misc.dsdb_attach_schema_from_ldif_file(self, pf, df) + + def set_invocation_id(self, invocation_id): + """Set the invocation id for this SamDB handle. + + :param invocation_id: GUID of the invocation id. + """ + misc.dsdb_set_ntds_invocation_id(self, invocation_id) + + def setexpiry(self, user, expiry_seconds, noexpiry): + """Set the password expiry for a user + + :param expiry_seconds: expiry time from now in seconds + :param noexpiry: if set, then don't expire password + """ + self.transaction_start(); + res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE, + expression=("(samAccountName=%s)" % user), + attrs=["userAccountControl", "accountExpires"]) + assert len(res) == 1 + userAccountControl = int(res[0]["userAccountControl"][0]) + accountExpires = int(res[0]["accountExpires"][0]) + if noexpiry: + userAccountControl = userAccountControl | 0x10000 + accountExpires = 0 + else: + userAccountControl = userAccountControl & ~0x10000 + accountExpires = misc.unix2nttime(expiry_seconds + int(time.time())) + + mod = """ +dn: %s +changetype: modify +replace: userAccountControl +userAccountControl: %u +replace: accountExpires +accountExpires: %u +""" % (res[0].dn, userAccountControl, accountExpires) + # now change the database + self.modify_ldif(mod) + self.transaction_commit(); diff --git a/source4/scripting/python/samba/samr.py b/source4/scripting/python/samba/samr.py new file mode 100644 index 0000000000..62a7c6eb3d --- /dev/null +++ b/source4/scripting/python/samba/samr.py @@ -0,0 +1,759 @@ +import dcerpc + +def sid_to_string(sid): + """Convert a Python dictionary SID to a string SID.""" + + result = 'S-%d' % sid.sid_rev_num + + result = result + '-%u' % \ + (dcerpc.uint8_array_getitem(sid.id_auth, 5) + + (dcerpc.uint8_array_getitem(sid.id_auth, 4) << 8) + + (dcerpc.uint8_array_getitem(sid.id_auth, 3) << 16) + + (dcerpc.uint8_array_getitem(sid.id_auth, 2) << 24)) + + for i in range(0, sid.num_auths): + result = result + '-%u' % \ + dcerpc.uint32_array_getitem(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():] + + sid = dcerpc.dom_sid() + sid.sid_rev_num = sid_rev_num + sid.id_auth = dcerpc.new_uint8_array(6) + for i in range(6): + dcerpc.uint8_array_setitem(sid.id_auth, i, id_auth[i]) + sid.num_auths = num_auths + sid.sub_auths = dcerpc.new_uint32_array(num_auths) + for i in range(num_auths): + dcerpc.uint32_array_setitem(sid.sub_auths, i, sub_auths[i]) + + return sid + +def call_fn(fn, pipe, args): + """Wrap up a RPC call and throw an exception is an error was returned.""" + + result = fn(pipe, args); + + if result & 0xc0000000L: + raise dcerpc.NTSTATUS(result, dcerpc.nt_errstr(result)); + + return result; + + +class SamrHandle(object): + + def __init__(self, pipe, handle): + + self.pipe = pipe + self.handle = handle + + def __del__(self): + + if self.handle is not None: + self.Close() + + def Close(self): + + r = dcerpc.samr_Close() + r.data_in.handle = self.handle + + call_fn(dcerpc.dcerpc_samr_Close, self.pipe, r) + + self.handle = None + + def QuerySecurity(self, sec_info = 7): + + r = dcerpc.samr_QuerySecurity() + r.data_in.handle = self.handle + r.data_in.sec_info = sec_info + + call_fn(dcerpc.dcerpc_samr_QuerySecurity, self.pipe, r) + + return r.data_out.sdbuf + + def SetSecurity(self, sdbuf, sec_info = 7): + + r = dcerpc.samr_SetSecurity() + r.data_in.handle = self.handle + r.data_in.sec_info = sec_info + r.data_in.sdbuf = sdbuf + + call_fn(dcerpc.dcerpc_samr_SetSecurity, self.pipe, r) + + +class ConnectHandle(SamrHandle): + + def EnumDomains(self): + + r = dcerpc.samr_EnumDomains() + r.data_in.connect_handle = self.handle + r.data_in.resume_handle = 0 + r.data_in.buf_size = -1 + + domains = [] + + while 1: + + call_fn(dcerpc.dcerpc_samr_EnumDomains, self.pipe, r) + + for i in range(r.data_out.sam.count): + domains.append(dcerpc.samr_SamEntry_array_getitem( + r.data_out.sam.entries, i).name.string) + + # TODO: Handle more entries here + + break + + return domains + + def LookupDomain(self, domain_name): + + r = dcerpc.samr_LookupDomain() + r.data_in.connect_handle = self.handle + r.data_in.domain_name = dcerpc.samr_String() + r.data_in.domain_name.string = domain_name + + call_fn(dcerpc.dcerpc_samr_LookupDomain, self.pipe, r) + + return sid_to_string(r.data_out.sid); + + def OpenDomain(self, domain_sid, access_mask = 0x02000000): + + r = dcerpc.samr_OpenDomain() + r.data_in.connect_handle = self.handle + r.data_in.access_mask = access_mask + r.data_in.sid = string_to_sid(domain_sid) + + call_fn(dcerpc.dcerpc_samr_OpenDomain, self.pipe, r) + + return DomainHandle(self.pipe, r.data_out.domain_handle) + + def Shutdown(self): + + r = dcerpc.samr_Shutdown() + r.data_in.connect_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_Shutdown, self.pipe, r) + + def GetDomPwInfo(self, domain_name): + + r = dcerpc.samr_GetDomPwInfo() + r.data_in.domain_name = dcerpc.samr_String() + r.data_in.domain_name.string = domain_name + + call_fn(dcerpc.dcerpc_samr_GetDomPwInfo, self.pipe, r) + + return r.data_out.info + + + def SetBootKeyInformation(self, unknown1, unknown2, unknown3): + + r = dcerpc.samr_GetBootKeyInformation() + r.data_in.connect_handle = self.handle + r.data_in.unknown1 = unknown1 + r.data_in.unknown2 = unknown2 + r.data_in.unknown3 = unknown3 + + call_fn(dcerpc.dcerpc_samr_SetBootKeyInformation, self.pipe, r) + + +class DomainHandle(SamrHandle): + + def QueryDomainInfo(self, level = 2): + + r = dcerpc.samr_QueryDomainInfo() + r.data_in.domain_handle = self.handle + r.data_in.level = level + + call_fn(dcerpc.dcerpc_samr_QueryDomainInfo, self.pipe, r) + + return getattr(r.data_out.info, 'info%d' % level) + + def QueryDomainInfo2(self, level = 2): + + r = dcerpc.samr_QueryDomainInfo2() + r.data_in.domain_handle = self.handle + r.data_in.level = level + + call_fn(dcerpc.dcerpc_samr_QueryDomainInfo2, self.pipe, r) + + return getattr(r.data_out.info, 'info%d' % level) + + def SetDomainInfo(self, level, info): + + r = dcerpc.samr_SetDomainInfo() + r.data_in.domain_handle = self.handle + r.data_in.level = level + r.data_in.info = dcerpc.samr_DomainInfo() + setattr(r.data_in.info, 'info%d' % level, info) + + call_fn(dcerpc.dcerpc_samr_SetDomainInfo, self.pipe, r) + + def EnumDomainGroups(self): + + r = dcerpc.samr_EnumDomainGroups() + r.data_in.domain_handle = self.handle + r.data_in.resume_handle = 0 + r.data_in.max_size = 1000 + + call_fn(dcerpc.dcerpc_samr_EnumDomainGroups, self.pipe, r) + + groups = [] + + if r.data_out.sam.entries: + for i in range(r.data_out.sam.count): + groups.append(dcerpc.samr_SamEntry_array_getitem( + r.data_out.sam.entries, i).name.string) + + return groups + + def EnumDomainAliases(self): + + r = dcerpc.samr_EnumDomainAliases() + r.data_in.domain_handle = self.handle + r.data_in.resume_handle = 0 + # acct_flags in SamrEnumerateAliasesInDomain has probably + # no meaning so use 0xffffffff like W2K + r.data_in.acct_flags = 0xffffffffL + + call_fn(dcerpc.dcerpc_samr_EnumDomainAliases, self.pipe, r) + + aliases = [] + + if r.data_out.sam.entries: + for i in range(r.data_out.sam.count): + aliases.append(dcerpc.samr_SamEntry_array_getitem( + r.data_out.sam.entries, i).name.string) + + return aliases + + def EnumDomainUsers(self, user_account_flags = 16): + + r = dcerpc.samr_EnumDomainUsers() + r.data_in.domain_handle = self.handle + r.data_in.resume_handle = 0 + r.data_in.acct_flags = user_account_flags + r.data_in.max_size = 1000 + + call_fn(dcerpc.dcerpc_samr_EnumDomainUsers, self.pipe, r) + + users = [] + + if r.data_out.sam.entries: + for i in range(r.data_out.sam.count): + users.append(dcerpc.samr_SamEntry_array_getitem( + r.data_out.sam.entries, i).name.string) + + return users + + def CreateUser(self, account_name, access_mask = 0x02000000): + + r = dcerpc.samr_CreateUser() + r.data_in.domain_handle = self.handle + r.data_in.account_name = dcerpc.samr_String() + r.data_in.account_name.string = account_name + r.data_in.access_mask = access_mask + + call_fn(dcerpc.dcerpc_samr_CreateUser, self.pipe, r) + + return (r.data_out.user_handle, + dcerpc.uint32_array_getitem(r.data_out.rid, 0)) + + def CreateUser2(self, account_name, acct_flags = 0x00000010, + access_mask = 0x02000000): + + r = dcerpc.samr_CreateUser2() + r.data_in.domain_handle = self.handle + r.data_in.account_name = dcerpc.samr_String() + r.data_in.account_name.string = account_name + r.data_in.acct_flags = acct_flags + r.data_in.access_mask = access_mask + + call_fn(dcerpc.dcerpc_samr_CreateUser2, self.pipe, r) + + return (r.data_out.user_handle, + dcerpc.uint32_array_getitem(r.data_out.access_granted, 0), + dcerpc.uint32_array_getitem(r.data_out.rid, 0)) + + def OpenUser(self, rid, access_mask = 0x02000000): + + r = dcerpc.samr_OpenUser() + r.data_in.domain_handle = self.handle + r.data_in.access_mask = access_mask + r.data_in.rid = rid + + call_fn(dcerpc.dcerpc_samr_OpenUser, self.pipe, r) + + return UserHandle(self.pipe, r.data_out.user_handle) + + def OpenGroup(self, rid, access_mask = 0x02000000): + + r = dcerpc.samr_OpenGroup() + r.data_in.domain_handle = self.handle + r.data_in.access_mask = access_mask + r.data_in.rid = rid + + call_fn(dcerpc.dcerpc_samr_OpenGroup, self.pipe, r) + + return GroupHandle(self.pipe, r.data_out.group_handle) + + def OpenAlias(self, rid, access_mask = 0x02000000): + + r = dcerpc.samr_OpenAlias() + r.data_in.domain_handle = self.handle + r.data_in.access_mask = access_mask + r.data_in.rid = rid + + call_fn(dcerpc.dcerpc_samr_OpenAlias, self.pipe, r) + + return AliasHandle(self.pipe, r.data_out.alias_handle) + + def CreateDomAlias(self, alias_name, access_mask = 0x02000000): + + r = dcerpc.samr_CreateDomAlias() + r.data_in.domain_handle = self.handle + r.data_in.alias_name = dcerpc.samr_String() + r.data_in.alias_name.string = alias_name + r.data_in.access_mask = access_mask + + call_fn(dcerpc.dcerpc_samr_CreateDomAlias, self.pipe, r) + + return (AliasHandle(self.pipe, r.data_out.alias_handle), + r.data_out.rid) + + def RidToSid(self, rid): + + r = dcerpc.samr_RidToSid() + r.data_in.domain_handle = self.handle + r.data_in.rid = rid + + call_fn(dcerpc.dcerpc_samr_RidToSid, self.pipe, r) + + return sid_to_string(r.data_out.sid) + + def RemoveMemberFromForeignDomain(self, sid): + + r = dcerpc.samr_RemoveMemberFromForeignDomain() + r.data_in.domain_handle = self.handle + r.data_in.sid = sid + + call_fn(dcerpc.dcerpc_samr_RemoveMemberFromForeignDomain, self.pipe, r) + + def LookupNames(self, names): + + r = dcerpc.samr_LookupNames() + r.data_in.domain_handle = self.handle + r.data_in.num_names = len(names) + r.data_in.names = dcerpc.new_samr_String_array(len(names)) + + for i in range(len(names)): + s = dcerpc.samr_String() + s.string = names[i] + dcerpc.samr_String_array_setitem(r.data_in.names, i, s) + + call_fn(dcerpc.dcerpc_samr_LookupNames, self.pipe, r) + + return ([dcerpc.uint32_array_getitem(r.data_out.rids.ids, i) + for i in range(r.data_out.rids.count)], + [dcerpc.uint32_array_getitem(r.data_out.types.ids, i) + for i in range(r.data_out.types.count)]) + + def CreateDomainGroup(self, domain_name, access_mask = 0x02000000): + + r = dcerpc.samr_CreateDomainGroup() + r.data_in.domain_handle = self.handle + r.data_in.name = dcerpc.samr_String() + r.data_in.name.string = domain_name + r.data_in.access_mask = access_mask + + call_fn(dcerpc.dcerpc_samr_CreateDomainGroup, self.pipe, r) + + def GetAliasMembership(self, sids): + + r = dcerpc.samr_GetAliasMembership() + r.data_in.domain_handle = self.handle + r.data_in.sids = dcerpc.lsa_SidArray() + r.data_in.sids.num_sids = len(sids) + r.data_in.sids.sids = dcerpc.new_lsa_SidPtr_array(len(sids)) + + for i in range(len(sids)): + s = dcerpc.lsa_SidPtr() + s.sid = string_to_sid(sids[i]) + dcerpc.lsa_SidPtr_array_setitem(r.data_in.sids.sids, i, s) + + call_fn(dcerpc.dcerpc_samr_GetAliasMembership, self.pipe, r) + + return [r.ids[x] for x in range(r.count)] + + def QueryDisplayInfo(self, level): + + # TODO: Handle more data returns + + r = dcerpc.samr_QueryDisplayInfo() + r.data_in.domain_handle = self.handle + r.data_in.level = level + r.data_in.start_idx = 0 + r.data_in.max_entries = 1000 + r.data_in.buf_size = -1 + + call_fn(dcerpc.dcerpc_samr_QueryDisplayInfo, self.pipe, r) + + # TODO: Return a mapping of the various samr_DispInfo + # structures here. + + return getattr(r.data_out.info, 'info%d' % level) + + def QueryDisplayInfo2(self, level): + + # TODO: Handle more data returns + + r = dcerpc.samr_QueryDisplayInfo2() + r.data_in.domain_handle = self.handle + r.data_in.level = level + r.data_in.start_idx = 0 + r.data_in.max_entries = 1000 + r.data_in.buf_size = -1 + + call_fn(dcerpc.dcerpc_samr_QueryDisplayInfo2, self.pipe, r) + + # TODO: Return a mapping of the various samr_DispInfo + # structures here. + + return getattr(r.data_out.info, 'info%d' % level) + + def QueryDisplayInfo3(self, level): + + # TODO: Handle more data returns + + r = dcerpc.samr_QueryDisplayInfo3() + r.data_in.domain_handle = self.handle + r.data_in.level = level + r.data_in.start_idx = 0 + r.data_in.max_entries = 1000 + r.data_in.buf_size = -1 + + call_fn(dcerpc.dcerpc_samr_QueryDisplayInfo3, self.pipe, r) + + # TODO: Return a mapping of the various samr_DispInfo + # structures here. + + return getattr(r.data_out.info, 'info%d' % level) + + def GetBootKeyInformation(self): + + r = dcerpc.samr_GetBootKeyInformation() + r.data_in.domain_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_GetBootKeyInformation, self.pipe, r) + + return r.data_out.unknown + + def SetBootKeyInformation(self): + + r = dcerpc.samr_GetBootKeyInformation() + r.data_in.domain_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_GetBootKeyInformation, self.pipe, r) + + def TestPrivateFunctionsDomain(self): + + r = dcerpc.samr_TestPrivateFunctionsDomain() + r.data_in.domain_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_TestPrivateFunctionsDomain, self.pipe, r) + + +class UserHandle(SamrHandle): + + def DeleteUser(self): + + r = dcerpc.samr_DeleteUser() + r.data_in.user_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_DeleteUser, self.pipe, r) + + self.handle = None + + def GetUserPwInfo(self): + + r = dcerpc.samr_GetUserPwInfo() + r.data_in.user_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_GetUserPwInfo, self.pipe, r) + + return r.data_out.info + + def QueryUserInfo(self, level): + + r = dcerpc.samr_QueryUserInfo() + r.data_in.user_handle = self.handle + r.data_in.level = level + + call_fn(dcerpc.dcerpc_samr_QueryUserInfo, self.pipe, r) + + return r.data_out.info + + def QueryUserInfo2(self, level): + + r = dcerpc.samr_QueryUserInfo2() + r.data_in.user_handle = self.handle + r.data_in.level = level + + call_fn(dcerpc.dcerpc_samr_QueryUserInfo2, self.pipe, r) + + return r.data_out.info + + def GetGroupsForUser(self): + + r = dcerpc.samr_GetGroupsForUser() + r.data_in.user_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_GetGroupsForUser, self.pipe, r) + + rid_types = [dcerpc.samr_RidType_array_getitem(r.data_out.rids.rid, x) + for x in range(r.data_out.rids.count)] + + return [(x.rid, x.type) for x in rid_types] + + def TestPrivateFunctionsUser(self): + + r = dcerpc.samr_TestPrivateFunctionsUser() + r.data_in.user_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_TestPrivateFunctionsUser, self.pipe, r) + + +class GroupHandle(SamrHandle): + + def QueryGroupInfo(self, level): + + r = dcerpc.samr_QueryGroupInfo() + r.data_in.group_handle = self.handle + r.data_in.level = level + + call_fn(dcerpc.dcerpc_samr_QueryGroupInfo, self.pipe, r) + + return r.data_out.info + + def SetGroupInfo(self, level, info): + + r = dcerpc.samr_SetGroupInfo() + r.data_in.group_handle = self.handle + r.data_in.level = level + r.data_in.info = info + + call_fn(dcerpc.dcerpc_samr_SetGroupInfo, self.pipe, r) + + def QueryGroupMember(self): + + r = dcerpc.samr_QueryGroupMember() + r.data_in.group_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_QueryGroupMember, self.pipe, r) + + return [(dcerpc.uint32_array_getitem(r.data_out.rids.rids, x), + dcerpc.uint32_array_getitem(r.data_out.rids.unknown, x)) + for x in range(r.data_out.rids.count)] + + +class AliasHandle(SamrHandle): + + def DeleteDomAlias(self): + + r = dcerpc.samr_DeleteDomAlias() + r.data_in.alias_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_DeleteDomAlias, self.pipe, r) + + self.handle = None + + def QueryAliasInfo(self, level = 1): + + r = dcerpc.samr_QueryAliasInfo() + r.data_in.alias_handle = self.handle + r.data_in.level = level + + call_fn(dcerpc.dcerpc_samr_QueryAliasInfo, self.pipe, r) + + return r.data_out.info + + def SetAliasInfo(self, level, info): + + r = dcerpc.samr_SetAliasInfo() + r.data_in.alias_handle = self.handle + r.data_in.level = level + r.data_in.info = info + + call_fn(dcerpc.dcerpc_samr_SetAliasInfo, self.pipe, r) + + def AddAliasMember(self, sid): + + r = dcerpc.samr_AddAliasMember() + r.data_in.alias_handle = self.handle + r.data_in.sid = string_to_sid(sid) + + call_fn(dcerpc.dcerpc_samr_AddAliasMember, self.pipe, r) + + def AddMultipleMembersToAlias(self, sids): + + r = dcerpc.samr_AddMultipleMembersToAlias() + r.data_in.alias_handle = self.handle + r.data_in.sids = dcerpc.lsa_SidArray() + r.data_in.sids.num_sids = len(sids) + r.data_in.sids.sids = dcerpc.new_lsa_SidPtr_array(len(sids)) + + for i in range(len(sids)): + s = dcerpc.lsa_SidPtr() + s.sid = string_to_sid(sids[i]) + dcerpc.lsa_SidPtr_array_setitem(r.data_in.sids.sids, i, s) + + call_fn(dcerpc.dcerpc_samr_AddMultipleMembersToAlias, self.pipe, r) + + def GetMembersInAlias(self): + + r = dcerpc.samr_GetMembersInAlias() + r.data_in.alias_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_GetMembersInAlias, self.pipe, r) + + return [ + sid_to_string( + dcerpc.lsa_SidPtr_array_getitem(r.data_out.sids.sids, x).sid) + for x in range(r.data_out.sids.num_sids)] + +def Connect(pipe, access_mask = 0x02000000): + + r = dcerpc.samr_Connect() + r.data_in.system_name = dcerpc.new_uint16_array(1) + dcerpc.uint16_array_setitem(r.data_in.system_name, 0, ord('\\')) + r.data_in.access_mask = access_mask + + call_fn(dcerpc.dcerpc_samr_Connect, pipe, r) + + return ConnectHandle(pipe, r.data_out.connect_handle) + +def Connect2(pipe, system_name = '', access_mask = 0x02000000): + """Connect to the SAMR pipe.""" + + r = dcerpc.samr_Connect2() + r.data_in.system_name = system_name + r.data_in.access_mask = access_mask + + call_fn(dcerpc.dcerpc_samr_Connect2, pipe, r) + + return ConnectHandle(pipe, r.data_out.connect_handle) + +def Connect3(pipe, system_name = '', access_mask = 0x02000000): + + r = dcerpc.samr_Connect3() + r.data_in.system_name = system_name + r.data_in.unknown = 0 + r.data_in.access_mask = access_mask + + call_fn(dcerpc.dcerpc_samr_Connect3, pipe, r) + + return ConnectHandle(pipe, r.data_out.connect_handle) + + +def Connect4(pipe, system_name = '', access_mask = 0x02000000): + + r = dcerpc.samr_Connect4() + r.data_in.system_name = system_name + r.data_in.unknown = 0 + r.data_in.access_mask = access_mask + + call_fn(dcerpc.dcerpc_samr_Connect4, pipe, r) + + return ConnectHandle(pipe, r.data_out.connect_handle) + +def Connect5(pipe, system_name = '', access_mask = 0x02000000): + + r = dcerpc.samr_Connect5() + r.data_in.system_name = system_name + r.data_in.access_mask = access_mask + r.data_in.level = 1 + r.data_in.info = dcerpc.new_samr_ConnectInfo_array(1) + r.data_in.info.unknown1 = 0 + r.data_in.info.unknown2 = 0 + + call_fn(dcerpc.dcerpc_samr_Connect5, pipe, r) + + return ConnectHandle(pipe, r.data_out.connect_handle) + +# AddGroupMember +# DeleteDomainGroup +# DeleteGroupMember +# SetMemberAttributesofGroup +# AddAliasMember +# DeleteAliasMember +# GetMembersinAlias +# SetUserInfo +# ChangePasswordUser +# GetDisplayEnumerationIndex +# RemoveMemberFromForeignDomain +# GetDisplayEnumerationIndex2 +# RemoveMultipleMembersFromAlias +# OemChangePasswordUser2 +# ChangePasswordUser2 +# SetUserInfo2 +# ChangePasswordUser3 +# SetDsrmPassword +# ValidatePassword diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py new file mode 100644 index 0000000000..d827bfa004 --- /dev/null +++ b/source4/scripting/python/samba/tests/__init__.py @@ -0,0 +1,98 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-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/>. +# + +"""Samba Python tests.""" + +import os +import ldb +import samba +import tempfile +import unittest + +class LdbTestCase(unittest.TestCase): + """Trivial test case for running tests against a LDB.""" + def setUp(self): + self.filename = os.tempnam() + self.ldb = samba.Ldb(self.filename) + + def set_modules(self, modules=[]): + """Change the modules for this Ldb.""" + m = ldb.Message() + m.dn = ldb.Dn(self.ldb, "@MODULES") + m["@LIST"] = ",".join(modules) + self.ldb.add(m) + self.ldb = samba.Ldb(self.filename) + + +class TestCaseInTempDir(unittest.TestCase): + def setUp(self): + super(TestCaseInTempDir, self).setUp() + self.tempdir = tempfile.mkdtemp() + + def tearDown(self): + super(TestCaseInTempDir, self).tearDown() + self.assertEquals([], os.listdir(self.tempdir)) + os.rmdir(self.tempdir) + + +class SubstituteVarTestCase(unittest.TestCase): + def test_empty(self): + self.assertEquals("", samba.substitute_var("", {})) + + def test_nothing(self): + self.assertEquals("foo bar", samba.substitute_var("foo bar", {"bar": "bla"})) + + def test_replace(self): + self.assertEquals("foo bla", samba.substitute_var("foo ${bar}", {"bar": "bla"})) + + def test_broken(self): + self.assertEquals("foo ${bdkjfhsdkfh sdkfh ", + samba.substitute_var("foo ${bdkjfhsdkfh sdkfh ", {"bar": "bla"})) + + def test_unknown_var(self): + self.assertEquals("foo ${bla} gsff", + samba.substitute_var("foo ${bla} gsff", {"bar": "bla"})) + + def test_check_all_substituted(self): + samba.check_all_substituted("nothing to see here") + self.assertRaises(Exception, samba.check_all_substituted, "Not subsituted: ${FOOBAR}") + + +class LdbExtensionTests(TestCaseInTempDir): + def test_searchone(self): + path = self.tempdir + "/searchone.ldb" + l = samba.Ldb(path) + try: + l.add({"dn": "foo=dc", "bar": "bla"}) + self.assertEquals("bla", l.searchone(basedn=ldb.Dn(l, "foo=dc"), attribute="bar")) + finally: + del l + os.unlink(path) + + +cmdline_loadparm = None +cmdline_credentials = None + +class RpcInterfaceTestCase(unittest.TestCase): + def get_loadparm(self): + assert cmdline_loadparm is not None + return cmdline_loadparm + + def get_credentials(self): + return cmdline_credentials diff --git a/source4/scripting/python/samba/tests/dcerpc/__init__.py b/source4/scripting/python/samba/tests/dcerpc/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/source4/scripting/python/samba/tests/dcerpc/__init__.py diff --git a/source4/scripting/python/samba/tests/dcerpc/bare.py b/source4/scripting/python/samba/tests/dcerpc/bare.py new file mode 100644 index 0000000000..cd939b8098 --- /dev/null +++ b/source4/scripting/python/samba/tests/dcerpc/bare.py @@ -0,0 +1,48 @@ +#!/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/>. +# + +from samba.dcerpc import ClientConnection +from unittest import TestCase +from samba.tests import cmdline_loadparm + + +class BareTestCase(TestCase): + def test_bare(self): + # Connect to the echo pipe + x = ClientConnection("ncalrpc:localhost[DEFAULT]", + ("60a15ec5-4de8-11d7-a637-005056a20182", 1), lp_ctx=cmdline_loadparm) + self.assertEquals("\x01\x00\x00\x00", x.request(0, chr(0) * 4)) + + def test_alter_context(self): + x = ClientConnection("ncalrpc:localhost[DEFAULT]", + ("12345778-1234-abcd-ef00-0123456789ac", 1), lp_ctx=cmdline_loadparm) + y = ClientConnection("ncalrpc:localhost", + ("60a15ec5-4de8-11d7-a637-005056a20182", 1), + basis_connection=x, lp_ctx=cmdline_loadparm) + x.alter_context(("60a15ec5-4de8-11d7-a637-005056a20182", 1)) + # FIXME: self.assertEquals("\x01\x00\x00\x00", x.request(0, chr(0) * 4)) + + def test_two_connections(self): + x = ClientConnection("ncalrpc:localhost[DEFAULT]", + ("60a15ec5-4de8-11d7-a637-005056a20182", 1), lp_ctx=cmdline_loadparm) + y = ClientConnection("ncalrpc:localhost", + ("60a15ec5-4de8-11d7-a637-005056a20182", 1), + basis_connection=x, lp_ctx=cmdline_loadparm) + self.assertEquals("\x01\x00\x00\x00", y.request(0, chr(0) * 4)) diff --git a/source4/scripting/python/samba/tests/dcerpc/registry.py b/source4/scripting/python/samba/tests/dcerpc/registry.py new file mode 100644 index 0000000000..526b2340cc --- /dev/null +++ b/source4/scripting/python/samba/tests/dcerpc/registry.py @@ -0,0 +1,50 @@ +#!/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/>. +# + +from samba.dcerpc import winreg +import unittest +from samba.tests import RpcInterfaceTestCase + + +class WinregTests(RpcInterfaceTestCase): + def setUp(self): + self.conn = winreg.winreg("ncalrpc:", self.get_loadparm(), + self.get_credentials()) + + def get_hklm(self): + return self.conn.OpenHKLM(None, + winreg.KEY_QUERY_VALUE | winreg.KEY_ENUMERATE_SUB_KEYS) + + def test_hklm(self): + handle = self.conn.OpenHKLM(None, + winreg.KEY_QUERY_VALUE | winreg.KEY_ENUMERATE_SUB_KEYS) + self.conn.CloseKey(handle) + + def test_getversion(self): + handle = self.get_hklm() + version = self.conn.GetVersion(handle) + self.assertEquals(int, version.__class__) + self.conn.CloseKey(handle) + + def test_getkeyinfo(self): + handle = self.conn.OpenHKLM(None, + winreg.KEY_QUERY_VALUE | winreg.KEY_ENUMERATE_SUB_KEYS) + x = self.conn.QueryInfoKey(handle, winreg.String()) + self.assertEquals(9, len(x)) # should return a 9-tuple + self.conn.CloseKey(handle) diff --git a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py new file mode 100644 index 0000000000..12638e2397 --- /dev/null +++ b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py @@ -0,0 +1,69 @@ +#!/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/>. +# + +from samba.dcerpc import echo +from samba.ndr import ndr_pack, ndr_unpack +import unittest +from samba.tests import RpcInterfaceTestCase + + +class RpcEchoTests(RpcInterfaceTestCase): + def setUp(self): + self.conn = echo.rpcecho("ncalrpc:", self.get_loadparm()) + + def test_two_contexts(self): + self.conn2 = echo.rpcecho("ncalrpc:", self.get_loadparm(), basis_connection=self.conn) + self.assertEquals(3, self.conn2.AddOne(2)) + + def test_abstract_syntax(self): + self.assertEquals(("60a15ec5-4de8-11d7-a637-005056a20182", 1), + self.conn.abstract_syntax) + + def test_addone(self): + self.assertEquals(2, self.conn.AddOne(1)) + + def test_echodata(self): + self.assertEquals([1,2,3], self.conn.EchoData([1, 2, 3])) + + def test_call(self): + self.assertEquals(u"foobar", self.conn.TestCall(u"foobar")) + + def test_surrounding(self): + surrounding_struct = echo.Surrounding() + surrounding_struct.x = 4 + surrounding_struct.surrounding = [1,2,3,4] + y = self.conn.TestSurrounding(surrounding_struct) + self.assertEquals(8 * [0], y.surrounding) + + def test_manual_request(self): + self.assertEquals("\x01\x00\x00\x00", self.conn.request(0, chr(0) * 4)) + + def test_server_name(self): + self.assertEquals(None, self.conn.server_name) + + +class NdrEchoTests(unittest.TestCase): + def test_info1_push(self): + x = echo.info1() + x.v = 42 + self.assertEquals("\x2a", ndr_pack(x)) + + def test_info1_pull(self): + x = ndr_unpack(echo.info1, "\x42") + self.assertEquals(x.v, 66) diff --git a/source4/scripting/python/samba/tests/dcerpc/sam.py b/source4/scripting/python/samba/tests/dcerpc/sam.py new file mode 100644 index 0000000000..50e00a3f9e --- /dev/null +++ b/source4/scripting/python/samba/tests/dcerpc/sam.py @@ -0,0 +1,46 @@ +#!/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/>. +# + +from samba.dcerpc import samr, security +from samba.tests import RpcInterfaceTestCase + +# FIXME: Pidl should be doing this for us +def toArray((handle, array, num_entries)): + ret = [] + for x in range(num_entries): + ret.append((array.entries[x].idx, array.entries[x].name)) + return ret + + +class SamrTests(RpcInterfaceTestCase): + def setUp(self): + self.conn = samr.samr("ncalrpc:", self.get_loadparm()) + + def test_connect5(self): + (level, info, handle) = self.conn.Connect5(None, 0, 1, samr.ConnectInfo1()) + + def test_connect2(self): + handle = self.conn.Connect2(None, security.SEC_FLAG_MAXIMUM_ALLOWED) + + def test_EnumDomains(self): + handle = self.conn.Connect2(None, security.SEC_FLAG_MAXIMUM_ALLOWED) + domains = toArray(self.conn.EnumDomains(handle, 0, -1)) + self.conn.Close(handle) + diff --git a/source4/scripting/python/samba/tests/dcerpc/unix.py b/source4/scripting/python/samba/tests/dcerpc/unix.py new file mode 100644 index 0000000000..aa47b71b16 --- /dev/null +++ b/source4/scripting/python/samba/tests/dcerpc/unix.py @@ -0,0 +1,37 @@ +#!/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/>. +# + +from samba.dcerpc import unixinfo +from samba.tests import RpcInterfaceTestCase + +class UnixinfoTests(RpcInterfaceTestCase): + def setUp(self): + self.conn = unixinfo.unixinfo("ncalrpc:", self.get_loadparm()) + + def test_getpwuid(self): + infos = self.conn.GetPWUid(range(512)) + self.assertEquals(512, len(infos)) + self.assertEquals("/bin/false", infos[0].shell) + self.assertTrue(isinstance(infos[0].homedir, unicode)) + + def test_gidtosid(self): + self.conn.GidToSid(1000) + + def test_uidtosid(self): + self.conn.UidToSid(1000) diff --git a/source4/scripting/python/samba/tests/provision.py b/source4/scripting/python/samba/tests/provision.py new file mode 100644 index 0000000000..352357f694 --- /dev/null +++ b/source4/scripting/python/samba/tests/provision.py @@ -0,0 +1,124 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-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 os +from samba.provision import setup_secretsdb, secretsdb_become_dc, findnss +import samba.tests +from ldb import Dn +from samba import param +import unittest + +lp = samba.tests.cmdline_loadparm + +setup_dir = "setup" +def setup_path(file): + return os.path.join(setup_dir, file) + + +class ProvisionTestCase(samba.tests.TestCaseInTempDir): + """Some simple tests for individual functions in the provisioning code. + """ + def test_setup_secretsdb(self): + path = os.path.join(self.tempdir, "secrets.ldb") + ldb = setup_secretsdb(path, setup_path, None, None, lp=lp) + try: + self.assertEquals("LSA Secrets", + ldb.searchone(basedn="CN=LSA Secrets", attribute="CN")) + finally: + del ldb + os.unlink(path) + + def test_become_dc(self): + path = os.path.join(self.tempdir, "secrets.ldb") + secrets_ldb = setup_secretsdb(path, setup_path, None, None, lp=lp) + try: + secretsdb_become_dc(secrets_ldb, setup_path, domain="EXAMPLE", + realm="example", netbiosname="myhost", + domainsid="S-5-22", keytab_path="keytab.path", + samdb_url="ldap://url/", + dns_keytab_path="dns.keytab", dnspass="bla", + machinepass="machinepass", dnsdomain="example.com") + self.assertEquals(1, + len(secrets_ldb.search("samAccountName=krbtgt,flatname=EXAMPLE,CN=Principals"))) + self.assertEquals("keytab.path", + secrets_ldb.searchone(basedn="flatname=EXAMPLE,CN=primary domains", + expression="(privateKeytab=*)", + attribute="privateKeytab")) + self.assertEquals("S-5-22", + secrets_ldb.searchone(basedn="flatname=EXAMPLE,CN=primary domains", + expression="objectSid=*", attribute="objectSid")) + + finally: + del secrets_ldb + os.unlink(path) + + +class FindNssTests(unittest.TestCase): + """Test findnss() function.""" + def test_nothing(self): + def x(y): + raise KeyError + self.assertRaises(KeyError, findnss, x, []) + + def test_first(self): + self.assertEquals("bla", findnss(lambda x: "bla", ["bla"])) + + def test_skip_first(self): + def x(y): + if y != "bla": + raise KeyError + return "ha" + self.assertEquals("ha", findnss(x, ["bloe", "bla"])) + + +class Disabled(object): + def test_setup_templatesdb(self): + raise NotImplementedError(self.test_setup_templatesdb) + + def test_setup_registry(self): + raise NotImplementedError(self.test_setup_registry) + + def test_setup_samdb_rootdse(self): + raise NotImplementedError(self.test_setup_samdb_rootdse) + + def test_setup_samdb_partitions(self): + raise NotImplementedError(self.test_setup_samdb_partitions) + + def test_create_phpldapadmin_config(self): + raise NotImplementedError(self.test_create_phpldapadmin_config) + + def test_provision_dns(self): + raise NotImplementedError(self.test_provision_dns) + + def test_provision_ldapbase(self): + raise NotImplementedError(self.test_provision_ldapbase) + + def test_provision_guess(self): + raise NotImplementedError(self.test_provision_guess) + + def test_join_domain(self): + raise NotImplementedError(self.test_join_domain) + + def test_vampire(self): + raise NotImplementedError(self.test_vampire) + + def test_erase_partitions(self): + raise NotImplementedError(self.test_erase_partitions) + + diff --git a/source4/scripting/python/samba/tests/samba3.py b/source4/scripting/python/samba/tests/samba3.py new file mode 100644 index 0000000000..1755cbdcf0 --- /dev/null +++ b/source4/scripting/python/samba/tests/samba3.py @@ -0,0 +1,210 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# 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 unittest +from samba.samba3 import (GroupMappingDatabase, Registry, PolicyDatabase, SecretsDatabase, TdbSam, + WinsDatabase, SmbpasswdFile, ACB_NORMAL, IdmapDatabase, SAMUser) +import os + +DATADIR=os.path.join(os.path.dirname(__file__), "../../../../../testdata/samba3") +print "Samba 3 data dir: %s" % DATADIR + +class RegistryTestCase(unittest.TestCase): + def setUp(self): + self.registry = Registry(os.path.join(DATADIR, "registry.tdb")) + + def tearDown(self): + self.registry.close() + + def test_length(self): + self.assertEquals(28, len(self.registry)) + + def test_keys(self): + self.assertTrue("HKLM" in self.registry.keys()) + + def test_subkeys(self): + self.assertEquals(["SOFTWARE", "SYSTEM"], self.registry.subkeys("HKLM")) + + def test_values(self): + self.assertEquals({'DisplayName': (1L, 'E\x00v\x00e\x00n\x00t\x00 \x00L\x00o\x00g\x00\x00\x00'), + 'ErrorControl': (4L, '\x01\x00\x00\x00')}, + self.registry.values("HKLM/SYSTEM/CURRENTCONTROLSET/SERVICES/EVENTLOG")) + + +class PolicyTestCase(unittest.TestCase): + def setUp(self): + self.policy = PolicyDatabase(os.path.join(DATADIR, "account_policy.tdb")) + + def test_policy(self): + self.assertEquals(self.policy.min_password_length, 5) + self.assertEquals(self.policy.minimum_password_age, 0) + self.assertEquals(self.policy.maximum_password_age, 999999999) + self.assertEquals(self.policy.refuse_machine_password_change, 0) + self.assertEquals(self.policy.reset_count_minutes, 0) + self.assertEquals(self.policy.disconnect_time, -1) + self.assertEquals(self.policy.user_must_logon_to_change_password, None) + self.assertEquals(self.policy.password_history, 0) + self.assertEquals(self.policy.lockout_duration, 0) + self.assertEquals(self.policy.bad_lockout_minutes, None) + + +class GroupsTestCase(unittest.TestCase): + def setUp(self): + self.groupdb = GroupMappingDatabase(os.path.join(DATADIR, "group_mapping.tdb")) + + def tearDown(self): + self.groupdb.close() + + def test_group_length(self): + self.assertEquals(13, len(list(self.groupdb.groupsids()))) + + def test_get_group(self): + self.assertEquals((-1, 5L, 'Administrators', ''), self.groupdb.get_group("S-1-5-32-544")) + + def test_groupsids(self): + sids = list(self.groupdb.groupsids()) + self.assertTrue("S-1-5-32-544" in sids) + + def test_alias_length(self): + self.assertEquals(0, len(list(self.groupdb.aliases()))) + + +class SecretsDbTestCase(unittest.TestCase): + def setUp(self): + self.secretsdb = SecretsDatabase(os.path.join(DATADIR, "secrets.tdb")) + + def tearDown(self): + self.secretsdb.close() + + def test_get_sid(self): + self.assertTrue(self.secretsdb.get_sid("BEDWYR") is not None) + + +class TdbSamTestCase(unittest.TestCase): + def setUp(self): + self.samdb = TdbSam(os.path.join(DATADIR, "passdb.tdb")) + + def tearDown(self): + self.samdb.close() + + def test_usernames(self): + self.assertEquals(3, len(list(self.samdb.usernames()))) + + def test_getuser(self): + user = SAMUser("root") + user.logoff_time = 2147483647 + user.kickoff_time = 2147483647 + user.pass_can_change_time = 1125418267 + user.username = "root" + user.uid = None + user.lm_password = 'U)\x02\x03\x1b\xed\xe9\xef\xaa\xd3\xb45\xb5\x14\x04\xee' + user.nt_password = '\x87\x8d\x80\x14`l\xda)gzD\xef\xa15?\xc7' + user.acct_ctrl = 16 + user.pass_last_set_time = 1125418267 + user.fullname = "root" + user.nt_username = "" + user.logoff_time = 2147483647 + user.acct_desc = "" + user.group_rid = 1001 + user.logon_count = 0 + user.bad_password_count = 0 + user.domain = "BEDWYR" + user.munged_dial = "" + user.workstations = "" + user.user_rid = 1000 + user.kickoff_time = 2147483647 + user.logoff_time = 2147483647 + user.unknown_6 = 1260L + user.logon_divs = 0 + user.hours = [True for i in range(168)] + other = self.samdb["root"] + for name in other.__dict__: + if other.__dict__[name] != user.__dict__[name]: + print "%s: %r != %r" % (name, other.__dict__[name], user.__dict__[name]) + self.assertEquals(user, other) + + +class WinsDatabaseTestCase(unittest.TestCase): + def setUp(self): + self.winsdb = WinsDatabase(os.path.join(DATADIR, "wins.dat")) + + def test_length(self): + self.assertEquals(22, len(self.winsdb)) + + def test_first_entry(self): + self.assertEqual((1124185120, ["192.168.1.5"], 0x64), self.winsdb["ADMINISTRATOR#03"]) + + def tearDown(self): + self.winsdb.close() + + +class SmbpasswdTestCase(unittest.TestCase): + def setUp(self): + self.samdb = SmbpasswdFile(os.path.join(DATADIR, "smbpasswd")) + + def test_length(self): + self.assertEquals(3, len(self.samdb)) + + def test_get_user(self): + user = SAMUser("rootpw") + user.lm_password = "552902031BEDE9EFAAD3B435B51404EE" + user.nt_password = "878D8014606CDA29677A44EFA1353FC7" + user.acct_ctrl = ACB_NORMAL + user.pass_last_set_time = int(1125418267) + user.uid = 0 + self.assertEquals(user, self.samdb["rootpw"]) + + def tearDown(self): + self.samdb.close() + + +class IdmapDbTestCase(unittest.TestCase): + def setUp(self): + self.idmapdb = IdmapDatabase(os.path.join(DATADIR, "winbindd_idmap.tdb")) + + def test_user_hwm(self): + self.assertEquals(10000, self.idmapdb.get_user_hwm()) + + def test_group_hwm(self): + self.assertEquals(10002, self.idmapdb.get_group_hwm()) + + def test_uids(self): + self.assertEquals(1, len(list(self.idmapdb.uids()))) + + def test_gids(self): + self.assertEquals(3, len(list(self.idmapdb.gids()))) + + def test_get_user_sid(self): + self.assertEquals("S-1-5-21-58189338-3053988021-627566699-501", self.idmapdb.get_user_sid(65534)) + + def test_get_group_sid(self): + self.assertEquals("S-1-5-21-2447931902-1787058256-3961074038-3007", self.idmapdb.get_group_sid(10001)) + + def tearDown(self): + self.idmapdb.close() + + +class ShareInfoTestCase(unittest.TestCase): + def setUp(self): + self.shareinfodb = ShareInfoDatabase(os.path.join(DATADIR, "share_info.tdb")) + + # FIXME: needs proper data so it can be tested + + def tearDown(self): + self.shareinfodb.close() diff --git a/source4/scripting/python/samba/tests/samdb.py b/source4/scripting/python/samba/tests/samdb.py new file mode 100644 index 0000000000..97be5672ce --- /dev/null +++ b/source4/scripting/python/samba/tests/samdb.py @@ -0,0 +1,84 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. Tests for SamDB +# 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/>. +# +from samba.auth import system_session +from samba.credentials import Credentials +import os +from samba.provision import setup_samdb, guess_names, setup_templatesdb, make_smbconf +from samba.samdb import SamDB +from samba.tests import cmdline_loadparm, TestCaseInTempDir +from samba import security +from unittest import TestCase +import uuid +from samba import param + +class SamDBTestCase(TestCaseInTempDir): + def setUp(self): + super(SamDBTestCase, self).setUp() + invocationid = str(uuid.uuid4()) + domaindn = "DC=COM,DC=EXAMPLE" + self.domaindn = domaindn + configdn = "CN=Configuration," + domaindn + schemadn = "CN=Schema," + configdn + domainguid = str(uuid.uuid4()) + policyguid = str(uuid.uuid4()) + setup_path = lambda x: os.path.join("setup", x) + creds = Credentials() + creds.set_anonymous() + domainsid = security.random_sid() + hostguid = str(uuid.uuid4()) + path = os.path.join(self.tempdir, "samdb.ldb") + session_info = system_session() + + hostname="foo" + domain="EXAMPLE" + dnsdomain="example.com" + serverrole="domain controller" + + smbconf = os.path.join(self.tempdir, "smb.conf") + make_smbconf(smbconf, setup_path, hostname, domain, dnsdomain, serverrole, + self.tempdir) + + lp = param.LoadParm() + lp.load(smbconf) + + names = guess_names(lp=lp, hostname=hostname, + domain=domain, dnsdomain=dnsdomain, + serverrole=serverrole, + domaindn=self.domaindn, configdn=configdn, + schemadn=schemadn) + setup_templatesdb(os.path.join(self.tempdir, "templates.ldb"), + setup_path, session_info=session_info, + credentials=creds, lp=cmdline_loadparm) + self.samdb = setup_samdb(path, setup_path, session_info, creds, + cmdline_loadparm, names, + lambda x: None, domainsid, + "# no aci", domainguid, + policyguid, False, "secret", + "secret", "secret", invocationid, + "secret", "domain controller") + + def tearDown(self): + for f in ['templates.ldb', 'schema.ldb', 'configuration.ldb', + 'users.ldb', 'samdb.ldb', 'smb.conf']: + os.remove(os.path.join(self.tempdir, f)) + super(SamDBTestCase, self).tearDown() + + def test_add_foreign(self): + self.samdb.add_foreign(self.domaindn, "S-1-5-7", "Somedescription") + diff --git a/source4/scripting/python/samba/tests/upgrade.py b/source4/scripting/python/samba/tests/upgrade.py new file mode 100644 index 0000000000..4dc86ace8a --- /dev/null +++ b/source4/scripting/python/samba/tests/upgrade.py @@ -0,0 +1,37 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# 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/>. +# + +from samba import Ldb +from samba.upgrade import import_wins +from samba.tests import LdbTestCase + +class WinsUpgradeTests(LdbTestCase): + def test_upgrade(self): + winsdb = { + "FOO#20": (200, ["127.0.0.1", "127.0.0.2"], 0x60) + } + import_wins(self.ldb, winsdb) + + self.assertEquals(['name=FOO,type=0x20'], + [str(m.dn) for m in self.ldb.search(expression="(objectClass=winsRecord)")]) + + def test_version(self): + import_wins(self.ldb, {}) + self.assertEquals("VERSION", + self.ldb.search(expression="(objectClass=winsMaxVersion)")[0]["cn"]) diff --git a/source4/scripting/python/samba/torture/pytorture b/source4/scripting/python/samba/torture/pytorture new file mode 100755 index 0000000000..e0123447e8 --- /dev/null +++ b/source4/scripting/python/samba/torture/pytorture @@ -0,0 +1,51 @@ +#!/usr/bin/python + +import sys +from optparse import OptionParser + +# Parse command line + +parser = OptionParser() + +parser.add_option("-b", "--binding", action="store", type="string", + dest="binding") + +parser.add_option("-d", "--domain", action="store", type="string", + dest="domain") + +parser.add_option("-u", "--username", action="store", type="string", + dest="username") + +parser.add_option("-p", "--password", action="store", type="string", + dest="password") + +(options, args) = parser.parse_args() + +if not options.binding: + parser.error('You must supply a binding string') + +if not options.username or not options.password or not options.domain: + parser.error('You must supply a domain, username and password') + +binding = options.binding +domain = options.domain +username = options.username +password = options.password + +if len(args) == 0: + parser.error('You must supply the name of a module to test') + +# Import and test + +for test in args: + + try: + module = __import__('torture_%s' % test) + except ImportError: + print 'No such module "%s"' % test + sys.exit(1) + + if not hasattr(module, 'runtests'): + print 'Module "%s" does not have a runtests function' % test + + module.runtests(binding, (domain, username, password)) diff --git a/source4/scripting/python/samba/torture/spoolss.py b/source4/scripting/python/samba/torture/spoolss.py new file mode 100644 index 0000000000..a75385e079 --- /dev/null +++ b/source4/scripting/python/samba/torture/spoolss.py @@ -0,0 +1,437 @@ +import sys, string +import dcerpc + + +def ResizeBufferCall(fn, pipe, r): + + r['buffer'] = None + r['buf_size'] = 0 + + result = fn(pipe, r) + + if result['result'] == dcerpc.WERR_INSUFFICIENT_BUFFER or \ + result['result'] == dcerpc.WERR_MORE_DATA: + r['buffer'] = result['buf_size'] * '\x00' + r['buf_size'] = result['buf_size'] + + result = fn(pipe, r) + + return result + + +def test_OpenPrinterEx(pipe, printer): + + print 'spoolss_OpenPrinterEx(%s)' % printer + + printername = '\\\\%s' % dcerpc.dcerpc_server_name(pipe) + + if printer is not None: + printername = printername + '\\%s' % printer + + r = {} + r['printername'] = printername + r['datatype'] = None + r['devmode_ctr'] = {} + r['devmode_ctr']['size'] = 0 + r['devmode_ctr']['devmode'] = None + r['access_mask'] = 0x02000000 + r['level'] = 1 + r['userlevel'] = {} + r['userlevel']['level1'] = {} + r['userlevel']['level1']['size'] = 0 + r['userlevel']['level1']['client'] = None + r['userlevel']['level1']['user'] = None + r['userlevel']['level1']['build'] = 1381 + r['userlevel']['level1']['major'] = 2 + r['userlevel']['level1']['minor'] = 0 + r['userlevel']['level1']['processor'] = 0 + + result = dcerpc.spoolss_OpenPrinterEx(pipe, r) + + return result['handle'] + + +def test_ClosePrinter(pipe, handle): + + r = {} + r['handle'] = handle + + dcerpc.spoolss_ClosePrinter(pipe, r) + + +def test_GetPrinter(pipe, handle): + + r = {} + r['handle'] = handle + + for level in [0, 1, 2, 3, 4, 5, 6, 7]: + + print 'spoolss_GetPrinter(level = %d)' % level + + r['level'] = level + r['buffer'] = None + r['buf_size'] = 0 + + result = ResizeBufferCall(dcerpc.spoolss_GetPrinter, pipe, r) + + +def test_EnumForms(pipe, handle): + + print 'spoolss_EnumForms()' + + r = {} + r['handle'] = handle + r['level'] = 1 + r['buffer'] = None + r['buf_size'] = 0 + + result = ResizeBufferCall(dcerpc.spoolss_EnumForms, pipe, r) + + forms = dcerpc.unmarshall_spoolss_FormInfo_array( + result['buffer'], r['level'], result['count']) + + for form in forms: + + r = {} + r['handle'] = handle + r['formname'] = form['info1']['formname'] + r['level'] = 1 + + result = ResizeBufferCall(dcerpc.spoolss_GetForm, pipe, r) + + +def test_EnumPorts(pipe, handle): + + print 'spoolss_EnumPorts()' + + for level in [1, 2]: + + r = {} + r['handle'] = handle + r['servername'] = None + r['level'] = level + + result = ResizeBufferCall(dcerpc.spoolss_EnumPorts, pipe, r) + + ports = dcerpc.unmarshall_spoolss_PortInfo_array( + result['buffer'], r['level'], result['count']) + + if level == 1: + port_names = map(lambda x: x['info1']['port_name'], ports) + + +def test_DeleteForm(pipe, handle, formname): + + r = {} + r['handle'] = handle + r['formname'] = formname + + dcerpc.spoolss_DeleteForm(pipe, r) + + +def test_GetForm(pipe, handle, formname): + + r = {} + r['handle'] = handle + r['formname'] = formname + r['level'] = 1 + + result = ResizeBufferCall(dcerpc.spoolss_GetForm, pipe, r) + + return result['info']['info1'] + + +def test_SetForm(pipe, handle, form): + + print 'spoolss_SetForm()' + + r = {} + r['handle'] = handle + r['level'] = 1 + r['formname'] = form['info1']['formname'] + r['info'] = form + + dcerpc.spoolss_SetForm(pipe, r) + + newform = test_GetForm(pipe, handle, r['formname']) + + if form['info1'] != newform: + print 'SetForm: mismatch: %s != %s' % \ + (r['info']['info1'], f) + sys.exit(1) + + +def test_AddForm(pipe, handle): + + print 'spoolss_AddForm()' + + formname = '__testform__' + + r = {} + r['handle'] = handle + r['level'] = 1 + r['info'] = {} + r['info']['info1'] = {} + r['info']['info1']['formname'] = formname + r['info']['info1']['flags'] = 0x0002 + r['info']['info1']['width'] = 100 + r['info']['info1']['length'] = 100 + r['info']['info1']['left'] = 0 + r['info']['info1']['top'] = 1000 + r['info']['info1']['right'] = 2000 + r['info']['info1']['bottom'] = 3000 + + try: + result = dcerpc.spoolss_AddForm(pipe, r) + except dcerpc.WERROR, arg: + if arg[0] == dcerpc.WERR_ALREADY_EXISTS: + test_DeleteForm(pipe, handle, formname) + result = dcerpc.spoolss_AddForm(pipe, r) + + f = test_GetForm(pipe, handle, formname) + + if r['info']['info1'] != f: + print 'AddForm: mismatch: %s != %s' % \ + (r['info']['info1'], f) + sys.exit(1) + + r['formname'] = formname + + test_SetForm(pipe, handle, r['info']) + + test_DeleteForm(pipe, handle, formname) + + +def test_EnumJobs(pipe, handle): + + print 'spoolss_EnumJobs()' + + r = {} + r['handle'] = handle + r['firstjob'] = 0 + r['numjobs'] = 0xffffffff + r['level'] = 1 + + result = ResizeBufferCall(dcerpc.spoolss_EnumJobs, pipe, r) + + if result['buffer'] is None: + return + + jobs = dcerpc.unmarshall_spoolss_JobInfo_array( + result['buffer'], r['level'], result['count']) + + for job in jobs: + + s = {} + s['handle'] = handle + s['job_id'] = job['info1']['job_id'] + s['level'] = 1 + + result = ResizeBufferCall(dcerpc.spoolss_GetJob, pipe, s) + + if result['info'] != job: + print 'EnumJobs: mismatch: %s != %s' % (result['info'], job) + sys.exit(1) + + + # TODO: AddJob, DeleteJob, ScheduleJob + + +def test_EnumPrinterData(pipe, handle): + + print 'test_EnumPrinterData()' + + enum_index = 0 + + while 1: + + r = {} + r['handle'] = handle + r['enum_index'] = enum_index + + r['value_offered'] = 0 + r['data_size'] = 0 + + result = dcerpc.spoolss_EnumPrinterData(pipe, r) + + r['value_offered'] = result['value_needed'] + r['data_size'] = result['data_size'] + + result = dcerpc.spoolss_EnumPrinterData(pipe, r) + + if result['result'] == dcerpc.WERR_NO_MORE_ITEMS: + break + + s = {} + s['handle'] = handle + s['value_name'] = result['value_name'] + + result2 = ResizeBufferCall(dcerpc.spoolss_GetPrinterData, pipe, s) + + if result['buffer'][:result2['buf_size']] != result2['buffer']: + print 'EnumPrinterData/GetPrinterData mismatch' + sys.exit(1) + + enum_index += 1 + + +def test_SetPrinterDataEx(pipe, handle): + + valuename = '__printerdataextest__' + data = '12345' + + r = {} + r['handle'] = handle + r['key_name'] = 'DsSpooler' + r['value_name'] = valuename + r['type'] = 3 + r['buffer'] = data + r['buf_size'] = len(data) + + result = dcerpc.spoolss_SetPrinterDataEx(pipe, r) + + +def test_EnumPrinterDataEx(pipe, handle): + + r = {} + r['handle'] = handle + r['key_name'] = 'DsSpooler' + r['buf_size'] = 0 + + result = dcerpc.spoolss_EnumPrinterDataEx(pipe, r) + + if result['result'] == dcerpc.WERR_MORE_DATA: + r['buf_size'] = result['buf_size'] + + result = dcerpc.spoolss_EnumPrinterDataEx(pipe, r) + + # TODO: test spoolss_GetPrinterDataEx() + + +def test_SetPrinterData(pipe, handle): + + print 'testing spoolss_SetPrinterData()' + + valuename = '__printerdatatest__' + data = '12345' + + r = {} + r['handle'] = handle + r['value_name'] = valuename + r['type'] = 3 # REG_BINARY + r['buffer'] = data + r['real_len'] = 5 + + dcerpc.spoolss_SetPrinterData(pipe, r) + + s = {} + s['handle'] = handle + s['value_name'] = valuename + + result = ResizeBufferCall(dcerpc.spoolss_GetPrinterData, pipe, r) + + if result['buffer'] != data: + print 'SetPrinterData: mismatch' + sys.exit(1) + + dcerpc.spoolss_DeletePrinterData(pipe, r) + + +def test_EnumPrinters(pipe): + + print 'testing spoolss_EnumPrinters()' + + printer_names = None + + r = {} + r['flags'] = 0x02 + r['server'] = None + + for level in [0, 1, 2, 4, 5]: + + print 'test_EnumPrinters(level = %d)' % level + + r['level'] = level + + result = ResizeBufferCall(dcerpc.spoolss_EnumPrinters, pipe, r) + + printers = dcerpc.unmarshall_spoolss_PrinterInfo_array( + result['buffer'], r['level'], result['count']) + + if level == 2: + for p in printers: + + # A nice check is for the specversion in the + # devicemode. This has always been observed to be + # 1025. + + if p['info2']['devmode']['specversion'] != 1025: + print 'test_EnumPrinters: specversion != 1025' + sys.exit(1) + + r['level'] = 1 + result = ResizeBufferCall(dcerpc.spoolss_EnumPrinters, pipe, r) + + for printer in dcerpc.unmarshall_spoolss_PrinterInfo_array( + result['buffer'], r['level'], result['count']): + + if string.find(printer['info1']['name'], '\\\\') == 0: + print 'Skipping remote printer %s' % printer['info1']['name'] + continue + + printername = string.split(printer['info1']['name'], ',')[0] + + handle = test_OpenPrinterEx(pipe, printername) + + test_GetPrinter(pipe, handle) + test_EnumPorts(pipe, handle) + test_EnumForms(pipe, handle) + test_AddForm(pipe, handle) + test_EnumJobs(pipe, handle) + test_EnumPrinterData(pipe, handle) + test_EnumPrinterDataEx(pipe, handle) + test_SetPrinterData(pipe, handle) +# test_SetPrinterDataEx(pipe, handle) + test_ClosePrinter(pipe, handle) + + +def test_EnumPrinterDrivers(pipe): + + print 'test spoolss_EnumPrinterDrivers()' + + for level in [1, 2, 3]: + + r = {} + r['server'] = None + r['environment'] = None + r['level'] = level + + result = ResizeBufferCall(dcerpc.spoolss_EnumPrinterDrivers, pipe, r) + + drivers = dcerpc.unmarshall_spoolss_DriverInfo_array( + result['buffer'], r['level'], result['count']) + + if level == 1: + driver_names = map(lambda x: x['info1']['driver_name'], drivers) + + +def test_PrintServer(pipe): + + handle = test_OpenPrinterEx(pipe, None) + + # EnumForms and AddForm tests return WERR_BADFID here (??) + + test_ClosePrinter(pipe, handle) + + +def runtests(binding, domain, username, password): + + print 'Testing SPOOLSS pipe' + + pipe = dcerpc.pipe_connect(binding, + dcerpc.DCERPC_SPOOLSS_UUID, dcerpc.DCERPC_SPOOLSS_VERSION, + domain, username, password) + + test_EnumPrinters(pipe) + test_EnumPrinterDrivers(pipe) + test_PrintServer(pipe) diff --git a/source4/scripting/python/samba/torture/torture_samr.py b/source4/scripting/python/samba/torture/torture_samr.py new file mode 100755 index 0000000000..15c6dc1a76 --- /dev/null +++ b/source4/scripting/python/samba/torture/torture_samr.py @@ -0,0 +1,221 @@ +#!/usr/bin/python + +import sys +import dcerpc, samr + +def test_Connect(pipe): + + handle = samr.Connect(pipe) + handle = samr.Connect2(pipe) + handle = samr.Connect3(pipe) + handle = samr.Connect4(pipe) + + # WIN2K3 only? + + try: + handle = samr.Connect5(pipe) + except dcerpc.NTSTATUS, arg: + if arg[0] != 0xc00000d2L: # NT_STATUS_NET_WRITE_FAULT + raise + + return handle + +def test_UserHandle(user_handle): + + # QuerySecurity()/SetSecurity() + + user_handle.SetSecurity(user_handle.QuerySecurity()) + + # GetUserPwInfo() + + user_handle.GetUserPwInfo() + + # GetUserInfo() + + for level in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 20, + 21, 23, 24, 25, 26]: + + try: + user_handle.QueryUserInfo(level) + user_handle.QueryUserInfo2(level) + except dcerpc.NTSTATUS, arg: + if arg[0] != 0xc0000003L: # NT_STATUS_INVALID_INFO_CLASS + raise + + # GetGroupsForUser() + + user_handle.GetGroupsForUser() + + # TestPrivateFunctionsUser() + + try: + user_handle.TestPrivateFunctionsUser() + except dcerpc.NTSTATUS, arg: + if arg[0] != 0xC0000002L: + raise + +def test_GroupHandle(group_handle): + + # QuerySecurity()/SetSecurity() + + group_handle.SetSecurity(group_handle.QuerySecurity()) + + # QueryGroupInfo() + + for level in [1, 2, 3, 4, 5]: + info = group_handle.QueryGroupInfo(level) + + # TODO: SetGroupinfo() + + # QueryGroupMember() + + group_handle.QueryGroupMember() + +def test_AliasHandle(alias_handle): + + # QuerySecurity()/SetSecurity() + + alias_handle.SetSecurity(alias_handle.QuerySecurity()) + + print alias_handle.GetMembersInAlias() + +def test_DomainHandle(name, sid, domain_handle): + + print 'testing %s (%s)' % (name, sid) + + # QuerySecurity()/SetSecurity() + + domain_handle.SetSecurity(domain_handle.QuerySecurity()) + + # LookupNames(), none mapped + + try: + domain_handle.LookupNames(['xxNONAMExx']) + except dcerpc.NTSTATUS, arg: + if arg[0] != 0xc0000073L: + raise dcerpc.NTSTATUS(arg) + + # LookupNames(), some mapped + + if name != 'Builtin': + domain_handle.LookupNames(['Administrator', 'xxNONAMExx']) + + # QueryDomainInfo()/SetDomainInfo() + + levels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13] + set_ok = [1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0] + + for i in range(len(levels)): + + info = domain_handle.QueryDomainInfo(level = levels[i]) + + try: + domain_handle.SetDomainInfo(levels[i], info) + except dcerpc.NTSTATUS, arg: + if not (arg[0] == 0xc0000003L and not set_ok[i]): + raise + + # QueryDomainInfo2() + + levels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13] + + for i in range(len(levels)): + domain_handle.QueryDomainInfo2(level = levels[i]) + + # EnumDomainUsers + + print 'testing users' + + users = domain_handle.EnumDomainUsers() + rids = domain_handle.LookupNames(users) + + for i in range(len(users)): + test_UserHandle(domain_handle.OpenUser(rids[0][i])) + + # QueryDisplayInfo + + for i in [1, 2, 3, 4, 5]: + domain_handle.QueryDisplayInfo(level = i) + domain_handle.QueryDisplayInfo2(level = i) + domain_handle.QueryDisplayInfo3(level = i) + + # EnumDomainGroups + + print 'testing groups' + + groups = domain_handle.EnumDomainGroups() + rids = domain_handle.LookupNames(groups) + + for i in range(len(groups)): + test_GroupHandle(domain_handle.OpenGroup(rids[0][i])) + + # EnumDomainAliases + + print 'testing aliases' + + aliases = domain_handle.EnumDomainAliases() + rids = domain_handle.LookupNames(aliases) + + for i in range(len(aliases)): + test_AliasHandle(domain_handle.OpenAlias(rids[0][i])) + + # CreateUser + # CreateUser2 + # CreateDomAlias + # RidToSid + # RemoveMemberFromForeignDomain + # CreateDomainGroup + # GetAliasMembership + + # GetBootKeyInformation() + + try: + domain_handle.GetBootKeyInformation() + except dcerpc.NTSTATUS, arg: + pass + + # TestPrivateFunctionsDomain() + + try: + domain_handle.TestPrivateFunctionsDomain() + except dcerpc.NTSTATUS, arg: + if arg[0] != 0xC0000002L: + raise + +def test_ConnectHandle(connect_handle): + + print 'testing connect handle' + + # QuerySecurity/SetSecurity + + connect_handle.SetSecurity(connect_handle.QuerySecurity()) + + # Lookup bogus domain + + try: + connect_handle.LookupDomain('xxNODOMAINxx') + except dcerpc.NTSTATUS, arg: + if arg[0] != 0xC00000DFL: # NT_STATUS_NO_SUCH_DOMAIN + raise + + # Test all domains + + for domain_name in connect_handle.EnumDomains(): + + connect_handle.GetDomPwInfo(domain_name) + sid = connect_handle.LookupDomain(domain_name) + domain_handle = connect_handle.OpenDomain(sid) + + test_DomainHandle(domain_name, sid, domain_handle) + + # TODO: Test Shutdown() function + +def runtests(binding, creds): + + print 'Testing SAMR pipe' + + pipe = dcerpc.pipe_connect(binding, + dcerpc.DCERPC_SAMR_UUID, int(dcerpc.DCERPC_SAMR_VERSION), creds) + + handle = test_Connect(pipe) + test_ConnectHandle(handle) diff --git a/source4/scripting/python/samba/torture/torture_tdb.py b/source4/scripting/python/samba/torture/torture_tdb.py new file mode 100755 index 0000000000..7f97caf6cb --- /dev/null +++ b/source4/scripting/python/samba/torture/torture_tdb.py @@ -0,0 +1,90 @@ +#!/usr/bin/python + +import sys, os +import Tdb + +def fail(msg): + print 'FAILED:', msg + sys.exit(1) + +tdb_file = '/tmp/torture_tdb.tdb' + +# Create temporary tdb file + +t = Tdb.Tdb(tdb_file, flags = Tdb.CLEAR_IF_FIRST) + +# Check non-existent key throws KeyError exception + +try: + t['__none__'] +except KeyError: + pass +else: + fail('non-existent key did not throw KeyError') + +# Check storing key + +t['bar'] = '1234' +if t['bar'] != '1234': + fail('store key failed') + +# Check key exists + +if not t.has_key('bar'): + fail('has_key() failed for existing key') + +if t.has_key('__none__'): + fail('has_key() succeeded for non-existent key') + +# Delete key + +try: + del(t['__none__']) +except KeyError: + pass +else: + fail('delete of non-existent key did not throw KeyError') + +del t['bar'] +if t.has_key('bar'): + fail('delete of existing key did not delete key') + +# Clear all keys + +t.clear() +if len(t) != 0: + fail('clear failed to remove all keys') + +# Other dict functions + +t['a'] = '1' +t['ab'] = '12' +t['abc'] = '123' + +if len(t) != 3: + fail('len method produced wrong value') + +keys = t.keys() +values = t.values() +items = t.items() + +if set(keys) != set(['a', 'ab', 'abc']): + fail('keys method produced wrong values') + +if set(values) != set(['1', '12', '123']): + fail('values method produced wrong values') + +if set(items) != set([('a', '1'), ('ab', '12'), ('abc', '123')]): + fail('values method produced wrong values') + +t.close() + +# Re-open read-only + +t = Tdb.Tdb(tdb_file, open_flags = os.O_RDONLY) +t.keys() +t.close() + +# Clean up + +os.unlink(tdb_file) diff --git a/source4/scripting/python/samba/torture/winreg.py b/source4/scripting/python/samba/torture/winreg.py new file mode 100755 index 0000000000..eb60b9847e --- /dev/null +++ b/source4/scripting/python/samba/torture/winreg.py @@ -0,0 +1,165 @@ +#!/usr/bin/python + +import sys, dcerpc + +def test_OpenHKLM(pipe): + + r = {} + r['unknown'] = {} + r['unknown']['unknown0'] = 0x9038 + r['unknown']['unknown1'] = 0x0000 + r['access_required'] = 0x02000000 + + result = dcerpc.winreg_OpenHKLM(pipe, r) + + return result['handle'] + +def test_QueryInfoKey(pipe, handle): + + r = {} + r['handle'] = handle + r['class'] = {} + r['class']['name'] = None + + return dcerpc.winreg_QueryInfoKey(pipe, r) + +def test_CloseKey(pipe, handle): + + r = {} + r['handle'] = handle + + dcerpc.winreg_CloseKey(pipe, r) + +def test_FlushKey(pipe, handle): + + r = {} + r['handle'] = handle + + dcerpc.winreg_FlushKey(pipe, r) + +def test_GetVersion(pipe, handle): + + r = {} + r['handle'] = handle + + dcerpc.winreg_GetVersion(pipe, r) + +def test_GetKeySecurity(pipe, handle): + + r = {} + r['handle'] = handle + r['unknown'] = 4 + r['size'] = None + r['data'] = {} + r['data']['max_len'] = 0 + r['data']['data'] = '' + + result = dcerpc.winreg_GetKeySecurity(pipe, r) + + print result + + if result['result'] == dcerpc.WERR_INSUFFICIENT_BUFFER: + r['size'] = {} + r['size']['max_len'] = result['data']['max_len'] + r['size']['offset'] = 0 + r['size']['len'] = result['data']['max_len'] + + result = dcerpc.winreg_GetKeySecurity(pipe, r) + + print result + + sys.exit(1) + +def test_Key(pipe, handle, name, depth = 0): + + # Don't descend too far. Registries can be very deep. + + if depth > 2: + return + + try: + keyinfo = test_QueryInfoKey(pipe, handle) + except dcerpc.WERROR, arg: + if arg[0] == dcerpc.WERR_ACCESS_DENIED: + return + + test_GetVersion(pipe, handle) + + test_FlushKey(pipe, handle) + + test_GetKeySecurity(pipe, handle) + + # Enumerate values in this key + + r = {} + r['handle'] = handle + r['name_in'] = {} + r['name_in']['len'] = 0 + r['name_in']['max_len'] = (keyinfo['max_valnamelen'] + 1) * 2 + r['name_in']['buffer'] = {} + r['name_in']['buffer']['max_len'] = keyinfo['max_valnamelen'] + 1 + r['name_in']['buffer']['offset'] = 0 + r['name_in']['buffer']['len'] = 0 + r['type'] = 0 + r['value_in'] = {} + r['value_in']['max_len'] = keyinfo['max_valbufsize'] + r['value_in']['offset'] = 0 + r['value_in']['len'] = 0 + r['value_len1'] = keyinfo['max_valbufsize'] + r['value_len2'] = 0 + + for i in range(0, keyinfo['num_values']): + + r['enum_index'] = i + + dcerpc.winreg_EnumValue(pipe, r) + + # Recursively test subkeys of this key + + r = {} + r['handle'] = handle + r['key_name_len'] = 0 + r['unknown'] = 0x0414 + r['in_name'] = {} + r['in_name']['unknown'] = 0x20a + r['in_name']['key_name'] = {} + r['in_name']['key_name']['name'] = None + r['class'] = {} + r['class']['name'] = None + r['last_changed_time'] = {} + r['last_changed_time']['low'] = 0 + r['last_changed_time']['high'] = 0 + + for i in range(0, keyinfo['num_subkeys']): + + r['enum_index'] = i + + subkey = dcerpc.winreg_EnumKey(pipe, r) + + s = {} + s['handle'] = handle + s['keyname'] = {} + s['keyname']['name'] = subkey['out_name']['name'] + s['unknown'] = 0 + s['access_mask'] = 0x02000000 + + result = dcerpc.winreg_OpenKey(pipe, s) + + test_Key(pipe, result['handle'], name + '/' + s['keyname']['name'], + depth + 1) + + test_CloseKey(pipe, result['handle']) + + # Enumerate values + +def runtests(binding, domain, username, password): + + print 'Testing WINREG pipe' + + pipe = dcerpc.pipe_connect(binding, + dcerpc.DCERPC_WINREG_UUID, dcerpc.DCERPC_WINREG_VERSION, + domain, username, password) + + handle = test_OpenHKLM(pipe) + + test_Key(pipe, handle, 'HKLM') diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py new file mode 100644 index 0000000000..0c83604e82 --- /dev/null +++ b/source4/scripting/python/samba/upgrade.py @@ -0,0 +1,437 @@ +#!/usr/bin/python +# +# backend code for upgrading from Samba3 +# Copyright Jelmer Vernooij 2005-2007 +# Released under the GNU GPL v3 or later +# + +"""Support code for upgrading from Samba 3 to Samba 4.""" + +__docformat__ = "restructuredText" + +from provision import findnss, provision, FILL_DRS +import grp +import ldb +import time +import pwd +import uuid +import registry +from samba import Ldb +from samba.samdb import SamDB + +def import_sam_policy(samldb, samba3_policy, domaindn): + """Import a Samba 3 policy database.""" + samldb.modify_ldif(""" +dn: %s +changetype: modify +replace: minPwdLength +minPwdLength: %d +pwdHistoryLength: %d +minPwdAge: %d +maxPwdAge: %d +lockoutDuration: %d +samba3ResetCountMinutes: %d +samba3UserMustLogonToChangePassword: %d +samba3BadLockoutMinutes: %d +samba3DisconnectTime: %d + +""" % (dn, policy.min_password_length, + policy.password_history, policy.minimum_password_age, + policy.maximum_password_age, policy.lockout_duration, + policy.reset_count_minutes, policy.user_must_logon_to_change_password, + policy.bad_lockout_minutes, policy.disconnect_time)) + + +def import_sam_account(samldb,acc,domaindn,domainsid): + """Import a Samba 3 SAM account. + + :param samldb: Samba 4 SAM Database handle + :param acc: Samba 3 account + :param domaindn: Domain DN + :param domainsid: Domain SID.""" + if acc.nt_username is None or acc.nt_username == "": + acc.nt_username = acc.username + + if acc.fullname is None: + try: + acc.fullname = pwd.getpwnam(acc.username)[4].split(",")[0] + except KeyError: + pass + + if acc.fullname is None: + acc.fullname = acc.username + + assert acc.fullname is not None + assert acc.nt_username is not None + + samldb.add({ + "dn": "cn=%s,%s" % (acc.fullname, domaindn), + "objectClass": ["top", "user"], + "lastLogon": str(acc.logon_time), + "lastLogoff": str(acc.logoff_time), + "unixName": acc.username, + "sAMAccountName": acc.nt_username, + "cn": acc.nt_username, + "description": acc.acct_desc, + "primaryGroupID": str(acc.group_rid), + "badPwdcount": str(acc.bad_password_count), + "logonCount": str(acc.logon_count), + "samba3Domain": acc.domain, + "samba3DirDrive": acc.dir_drive, + "samba3MungedDial": acc.munged_dial, + "samba3Homedir": acc.homedir, + "samba3LogonScript": acc.logon_script, + "samba3ProfilePath": acc.profile_path, + "samba3Workstations": acc.workstations, + "samba3KickOffTime": str(acc.kickoff_time), + "samba3BadPwdTime": str(acc.bad_password_time), + "samba3PassLastSetTime": str(acc.pass_last_set_time), + "samba3PassCanChangeTime": str(acc.pass_can_change_time), + "samba3PassMustChangeTime": str(acc.pass_must_change_time), + "objectSid": "%s-%d" % (domainsid, acc.user_rid), + "lmPwdHash:": acc.lm_password, + "ntPwdHash:": acc.nt_password, + }) + + +def import_sam_group(samldb, sid, gid, sid_name_use, nt_name, comment, domaindn): + """Upgrade a SAM group. + + :param samldb: SAM database. + :param gid: Group GID + :param sid_name_use: SID name use + :param nt_name: NT Group Name + :param comment: NT Group Comment + :param domaindn: Domain DN + """ + + if sid_name_use == 5: # Well-known group + return None + + if nt_name in ("Domain Guests", "Domain Users", "Domain Admins"): + return None + + if gid == -1: + gr = grp.getgrnam(nt_name) + else: + gr = grp.getgrgid(gid) + + if gr is None: + unixname = "UNKNOWN" + else: + unixname = gr.gr_name + + assert unixname is not None + + samldb.add({ + "dn": "cn=%s,%s" % (nt_name, domaindn), + "objectClass": ["top", "group"], + "description": comment, + "cn": nt_name, + "objectSid": sid, + "unixName": unixname, + "samba3SidNameUse": str(sid_name_use) + }) + + +def import_idmap(samdb,samba3_idmap,domaindn): + """Import idmap data. + + :param samdb: SamDB handle. + :param samba3_idmap: Samba 3 IDMAP database to import from + :param domaindn: Domain DN. + """ + samdb.add({ + "dn": domaindn, + "userHwm": str(samba3_idmap.get_user_hwm()), + "groupHwm": str(samba3_idmap.get_group_hwm())}) + + for uid in samba3_idmap.uids(): + samdb.add({"dn": "SID=%s,%s" % (samba3_idmap.get_user_sid(uid), domaindn), + "SID": samba3_idmap.get_user_sid(uid), + "type": "user", + "unixID": str(uid)}) + + for gid in samba3_idmap.uids(): + samdb.add({"dn": "SID=%s,%s" % (samba3_idmap.get_group_sid(gid), domaindn), + "SID": samba3_idmap.get_group_sid(gid), + "type": "group", + "unixID": str(gid)}) + + +def import_wins(samba4_winsdb, samba3_winsdb): + """Import settings from a Samba3 WINS database. + + :param samba4_winsdb: WINS database to import to + :param samba3_winsdb: WINS database to import from + """ + version_id = 0 + + for (name, (ttl, ips, nb_flags)) in samba3_winsdb.items(): + version_id+=1 + + type = int(name.split("#", 1)[1], 16) + + if type == 0x1C: + rType = 0x2 + elif type & 0x80: + if len(ips) > 1: + rType = 0x2 + else: + rType = 0x1 + else: + if len(ips) > 1: + rType = 0x3 + else: + rType = 0x0 + + if ttl > time.time(): + rState = 0x0 # active + else: + rState = 0x1 # released + + nType = ((nb_flags & 0x60)>>5) + + samba4_winsdb.add({"dn": "name=%s,type=0x%s" % tuple(name.split("#")), + "type": name.split("#")[1], + "name": name.split("#")[0], + "objectClass": "winsRecord", + "recordType": str(rType), + "recordState": str(rState), + "nodeType": str(nType), + "expireTime": ldb.timestring(ttl), + "isStatic": "0", + "versionID": str(version_id), + "address": ips}) + + samba4_winsdb.add({"dn": "cn=VERSION", + "cn": "VERSION", + "objectClass": "winsMaxVersion", + "maxVersion": str(version_id)}) + +def upgrade_provision(samba3, setup_dir, message, credentials, session_info, smbconf, targetdir): + oldconf = samba3.get_conf() + + if oldconf.get("domain logons") == "True": + serverrole = "domain controller" + else: + if oldconf.get("security") == "user": + serverrole = "standalone" + else: + serverrole = "member server" + + domainname = oldconf.get("workgroup") + if domainname: + domainname = str(domainname) + realm = oldconf.get("realm") + netbiosname = oldconf.get("netbios name") + + secrets_db = samba3.get_secrets_db() + + if domainname is None: + domainname = secrets_db.domains()[0] + message("No domain specified in smb.conf file, assuming '%s'" % domainname) + + if realm is None: + realm = domainname.lower() + message("No realm specified in smb.conf file, assuming '%s'\n" % realm) + + domainguid = secrets_db.get_domain_guid(domainname) + domainsid = secrets_db.get_sid(domainname) + if domainsid is None: + message("Can't find domain secrets for '%s'; using random SID\n" % domainname) + + if netbiosname is not None: + machinepass = secrets_db.get_machine_password(netbiosname) + else: + machinepass = None + + result = provision(setup_dir=setup_dir, message=message, + samdb_fill=FILL_DRS, smbconf=smbconf, session_info=session_info, + credentials=credentials, realm=realm, + domain=domainname, domainsid=domainsid, domainguid=domainguid, + machinepass=machinepass, serverrole=serverrole, targetdir=targetdir) + + import_wins(Ldb(result.paths.winsdb), samba3.get_wins_db()) + + # FIXME: import_registry(registry.Registry(), samba3.get_registry()) + + # FIXME: import_idmap(samdb,samba3.get_idmap_db(),domaindn) + + groupdb = samba3.get_groupmapping_db() + for sid in groupdb.groupsids(): + (gid, sid_name_use, nt_name, comment) = groupdb.get_group(sid) + # FIXME: import_sam_group(samdb, sid, gid, sid_name_use, nt_name, comment, domaindn) + + # FIXME: Aliases + + passdb = samba3.get_sam_db() + for name in passdb: + user = passdb[name] + #FIXME: import_sam_account(result.samdb, user, domaindn, domainsid) + + if hasattr(passdb, 'ldap_url'): + message("Enabling Samba3 LDAP mappings for SAM database") + + enable_samba3sam(result.samdb, passdb.ldap_url) + + +def enable_samba3sam(samdb, ldapurl): + """Enable Samba 3 LDAP URL database. + + :param samdb: SAM Database. + :param ldapurl: Samba 3 LDAP URL + """ + samdb.modify_ldif(""" +dn: @MODULES +changetype: modify +replace: @LIST +@LIST: samldb,operational,objectguid,rdn_name,samba3sam +""") + + samdb.add({"dn": "@MAP=samba3sam", "@MAP_URL": ldapurl}) + + +smbconf_keep = [ + "dos charset", + "unix charset", + "display charset", + "comment", + "path", + "directory", + "workgroup", + "realm", + "netbios name", + "netbios aliases", + "netbios scope", + "server string", + "interfaces", + "bind interfaces only", + "security", + "auth methods", + "encrypt passwords", + "null passwords", + "obey pam restrictions", + "password server", + "smb passwd file", + "private dir", + "passwd chat", + "password level", + "lanman auth", + "ntlm auth", + "client NTLMv2 auth", + "client lanman auth", + "client plaintext auth", + "read only", + "hosts allow", + "hosts deny", + "log level", + "debuglevel", + "log file", + "smb ports", + "large readwrite", + "max protocol", + "min protocol", + "unicode", + "read raw", + "write raw", + "disable netbios", + "nt status support", + "announce version", + "announce as", + "max mux", + "max xmit", + "name resolve order", + "max wins ttl", + "min wins ttl", + "time server", + "unix extensions", + "use spnego", + "server signing", + "client signing", + "max connections", + "paranoid server security", + "socket options", + "strict sync", + "max print jobs", + "printable", + "print ok", + "printer name", + "printer", + "map system", + "map hidden", + "map archive", + "preferred master", + "prefered master", + "local master", + "browseable", + "browsable", + "wins server", + "wins support", + "csc policy", + "strict locking", + "preload", + "auto services", + "lock dir", + "lock directory", + "pid directory", + "socket address", + "copy", + "include", + "available", + "volume", + "fstype", + "panic action", + "msdfs root", + "host msdfs", + "winbind separator"] + +def upgrade_smbconf(oldconf,mark): + """Remove configuration variables not present in Samba4 + + :param oldconf: Old configuration structure + :param mark: Whether removed configuration variables should be + kept in the new configuration as "samba3:<name>" + """ + data = oldconf.data() + newconf = param_init() + + for s in data: + for p in data[s]: + keep = False + for k in smbconf_keep: + if smbconf_keep[k] == p: + keep = True + break + + if keep: + newconf.set(s, p, oldconf.get(s, p)) + elif mark: + newconf.set(s, "samba3:"+p, oldconf.get(s,p)) + + return newconf + +SAMBA3_PREDEF_NAMES = { + 'HKLM': registry.HKEY_LOCAL_MACHINE, +} + +def import_registry(samba4_registry, samba3_regdb): + """Import a Samba 3 registry database into the Samba 4 registry. + + :param samba4_registry: Samba 4 registry handle. + :param samba3_regdb: Samba 3 registry database handle. + """ + def ensure_key_exists(keypath): + (predef_name, keypath) = keypath.split("/", 1) + predef_id = SAMBA3_PREDEF_NAMES[predef_name] + keypath = keypath.replace("/", "\\") + return samba4_registry.create_key(predef_id, keypath) + + for key in samba3_regdb.keys(): + key_handle = ensure_key_exists(key) + for subkey in samba3_regdb.subkeys(key): + ensure_key_exists(subkey) + for (value_name, (value_type, value_data)) in samba3_regdb.values(key).items(): + key_handle.set_value(value_name, value_type, value_data) + + diff --git a/source4/scripting/python/subunit/__init__.py b/source4/scripting/python/subunit/__init__.py new file mode 100644 index 0000000000..406cd8765b --- /dev/null +++ b/source4/scripting/python/subunit/__init__.py @@ -0,0 +1,388 @@ +# +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2005 Robert Collins <robertc@robertcollins.net> +# Copyright (C) 2007 Jelmer Vernooij <jelmer@samba.org> +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +import os +from StringIO import StringIO +import sys +import unittest + +def test_suite(): + import subunit.tests + return subunit.tests.test_suite() + + +def join_dir(base_path, path): + """ + Returns an absolute path to C{path}, calculated relative to the parent + of C{base_path}. + + @param base_path: A path to a file or directory. + @param path: An absolute path, or a path relative to the containing + directory of C{base_path}. + + @return: An absolute path to C{path}. + """ + return os.path.join(os.path.dirname(os.path.abspath(base_path)), path) + + +class TestProtocolServer(object): + """A class for receiving results from a TestProtocol client.""" + + OUTSIDE_TEST = 0 + TEST_STARTED = 1 + READING_FAILURE = 2 + READING_ERROR = 3 + + def __init__(self, client, stream=sys.stdout): + """Create a TestProtocol server instance. + + client should be an object that provides + - startTest + - addSuccess + - addFailure + - addError + - stopTest + methods, i.e. a TestResult. + """ + self.state = TestProtocolServer.OUTSIDE_TEST + self.client = client + self._stream = stream + + def _addError(self, offset, line): + if (self.state == TestProtocolServer.TEST_STARTED and + self.current_test_description == line[offset:-1]): + self.state = TestProtocolServer.OUTSIDE_TEST + self.current_test_description = None + self.client.addError(self._current_test, RemoteError("")) + self.client.stopTest(self._current_test) + self._current_test = None + elif (self.state == TestProtocolServer.TEST_STARTED and + self.current_test_description + " [" == line[offset:-1]): + self.state = TestProtocolServer.READING_ERROR + self._message = "" + else: + self.stdOutLineReceived(line) + + def _addFailure(self, offset, line): + if (self.state == TestProtocolServer.TEST_STARTED and + self.current_test_description == line[offset:-1]): + self.state = TestProtocolServer.OUTSIDE_TEST + self.current_test_description = None + self.client.addFailure(self._current_test, RemoteError()) + self.client.stopTest(self._current_test) + elif (self.state == TestProtocolServer.TEST_STARTED and + self.current_test_description + " [" == line[offset:-1]): + self.state = TestProtocolServer.READING_FAILURE + self._message = "" + else: + self.stdOutLineReceived(line) + + def _addSuccess(self, offset, line): + if (self.state == TestProtocolServer.TEST_STARTED and + self.current_test_description == line[offset:-1]): + self.client.addSuccess(self._current_test) + self.client.stopTest(self._current_test) + self.current_test_description = None + self._current_test = None + self.state = TestProtocolServer.OUTSIDE_TEST + else: + self.stdOutLineReceived(line) + + def _appendMessage(self, line): + if line[0:2] == " ]": + # quoted ] start + self._message += line[1:] + else: + self._message += line + + def endQuote(self, line): + if self.state == TestProtocolServer.READING_FAILURE: + self.state = TestProtocolServer.OUTSIDE_TEST + self.current_test_description = None + self.client.addFailure(self._current_test, + RemoteError(self._message)) + self.client.stopTest(self._current_test) + elif self.state == TestProtocolServer.READING_ERROR: + self.state = TestProtocolServer.OUTSIDE_TEST + self.current_test_description = None + self.client.addError(self._current_test, + RemoteError(self._message)) + self.client.stopTest(self._current_test) + else: + self.stdOutLineReceived(line) + + def lineReceived(self, line): + """Call the appropriate local method for the received line.""" + if line == "]\n": + self.endQuote(line) + elif (self.state == TestProtocolServer.READING_FAILURE or + self.state == TestProtocolServer.READING_ERROR): + self._appendMessage(line) + else: + parts = line.split(None, 1) + if len(parts) == 2: + cmd, rest = parts + offset = len(cmd) + 1 + cmd = cmd.strip(':') + if cmd in ('test', 'testing'): + self._startTest(offset, line) + elif cmd == 'error': + self._addError(offset, line) + elif cmd == 'failure': + self._addFailure(offset, line) + elif cmd in ('success', 'successful'): + self._addSuccess(offset, line) + else: + self.stdOutLineReceived(line) + else: + self.stdOutLineReceived(line) + + def lostConnection(self): + """The input connection has finished.""" + if self.state == TestProtocolServer.TEST_STARTED: + self.client.addError(self._current_test, + RemoteError("lost connection during test '%s'" + % self.current_test_description)) + self.client.stopTest(self._current_test) + elif self.state == TestProtocolServer.READING_ERROR: + self.client.addError(self._current_test, + RemoteError("lost connection during " + "error report of test " + "'%s'" % + self.current_test_description)) + self.client.stopTest(self._current_test) + elif self.state == TestProtocolServer.READING_FAILURE: + self.client.addError(self._current_test, + RemoteError("lost connection during " + "failure report of test " + "'%s'" % + self.current_test_description)) + self.client.stopTest(self._current_test) + + def readFrom(self, pipe): + for line in pipe.readlines(): + self.lineReceived(line) + self.lostConnection() + + def _startTest(self, offset, line): + """Internal call to change state machine. Override startTest().""" + if self.state == TestProtocolServer.OUTSIDE_TEST: + self.state = TestProtocolServer.TEST_STARTED + self._current_test = RemotedTestCase(line[offset:-1]) + self.current_test_description = line[offset:-1] + self.client.startTest(self._current_test) + else: + self.stdOutLineReceived(line) + + def stdOutLineReceived(self, line): + self._stream.write(line) + + +class RemoteException(Exception): + """An exception that occured remotely to python.""" + + def __eq__(self, other): + try: + return self.args == other.args + except AttributeError: + return False + + +class TestProtocolClient(unittest.TestResult): + """A class that looks like a TestResult and informs a TestProtocolServer.""" + + def __init__(self, stream): + super(TestProtocolClient, self).__init__() + self._stream = stream + + def addError(self, test, error): + """Report an error in test test.""" + self._stream.write("error: %s [\n" % (test.shortDescription() or str(test))) + for line in self._exc_info_to_string(error, test).splitlines(): + self._stream.write("%s\n" % line) + self._stream.write("]\n") + super(TestProtocolClient, self).addError(test, error) + + def addFailure(self, test, error): + """Report a failure in test test.""" + self._stream.write("failure: %s [\n" % (test.shortDescription() or str(test))) + for line in self._exc_info_to_string(error, test).splitlines(): + self._stream.write("%s\n" % line) + self._stream.write("]\n") + super(TestProtocolClient, self).addFailure(test, error) + + def addSuccess(self, test): + """Report a success in a test.""" + self._stream.write("successful: %s\n" % (test.shortDescription() or str(test))) + super(TestProtocolClient, self).addSuccess(test) + + def startTest(self, test): + """Mark a test as starting its test run.""" + self._stream.write("test: %s\n" % (test.shortDescription() or str(test))) + super(TestProtocolClient, self).startTest(test) + + +def RemoteError(description=""): + if description == "": + description = "\n" + return (RemoteException, RemoteException(description), None) + + +class RemotedTestCase(unittest.TestCase): + """A class to represent test cases run in child processes.""" + + def __eq__ (self, other): + try: + return self.__description == other.__description + except AttributeError: + return False + + def __init__(self, description): + """Create a psuedo test case with description description.""" + self.__description = description + + def error(self, label): + raise NotImplementedError("%s on RemotedTestCases is not permitted." % + label) + + def setUp(self): + self.error("setUp") + + def tearDown(self): + self.error("tearDown") + + def shortDescription(self): + return self.__description + + def id(self): + return "%s.%s" % (self._strclass(), self.__description) + + def __str__(self): + return "%s (%s)" % (self.__description, self._strclass()) + + def __repr__(self): + return "<%s description='%s'>" % \ + (self._strclass(), self.__description) + + def run(self, result=None): + if result is None: result = self.defaultTestResult() + result.startTest(self) + result.addError(self, RemoteError("Cannot run RemotedTestCases.\n")) + result.stopTest(self) + + def _strclass(self): + cls = self.__class__ + return "%s.%s" % (cls.__module__, cls.__name__) + + +class ExecTestCase(unittest.TestCase): + """A test case which runs external scripts for test fixtures.""" + + def __init__(self, methodName='runTest'): + """Create an instance of the class that will use the named test + method when executed. Raises a ValueError if the instance does + not have a method with the specified name. + """ + unittest.TestCase.__init__(self, methodName) + testMethod = getattr(self, methodName) + self.script = join_dir(sys.modules[self.__class__.__module__].__file__, + testMethod.__doc__) + + def countTestCases(self): + return 1 + + def run(self, result=None): + if result is None: result = self.defaultTestResult() + self._run(result) + + def debug(self): + """Run the test without collecting errors in a TestResult""" + self._run(unittest.TestResult()) + + def _run(self, result): + protocol = TestProtocolServer(result) + output = os.popen(self.script, mode='r') + protocol.readFrom(output) + + +class IsolatedTestCase(unittest.TestCase): + """A TestCase which runs its tests in a forked process.""" + + def run(self, result=None): + if result is None: result = self.defaultTestResult() + run_isolated(unittest.TestCase, self, result) + + +class IsolatedTestSuite(unittest.TestSuite): + """A TestCase which runs its tests in a forked process.""" + + def run(self, result=None): + if result is None: result = unittest.TestResult() + run_isolated(unittest.TestSuite, self, result) + + +def run_isolated(klass, self, result): + """Run a test suite or case in a subprocess, using the run method on klass. + """ + c2pread, c2pwrite = os.pipe() + # fixme - error -> result + # now fork + pid = os.fork() + if pid == 0: + # Child + # Close parent's pipe ends + os.close(c2pread) + # Dup fds for child + os.dup2(c2pwrite, 1) + # Close pipe fds. + os.close(c2pwrite) + + # at this point, sys.stdin is redirected, now we want + # to filter it to escape ]'s. + ### XXX: test and write that bit. + + result = TestProtocolClient(sys.stdout) + klass.run(self, result) + sys.stdout.flush() + sys.stderr.flush() + # exit HARD, exit NOW. + os._exit(0) + else: + # Parent + # Close child pipe ends + os.close(c2pwrite) + # hookup a protocol engine + protocol = TestProtocolServer(result) + protocol.readFrom(os.fdopen(c2pread, 'rU')) + os.waitpid(pid, 0) + # TODO return code evaluation. + return result + + +class SubunitTestRunner(object): + def __init__(self, stream=sys.stdout): + self.stream = stream + + def run(self, test): + "Run the given test case or test suite." + result = TestProtocolClient(self.stream) + test(result) + return result + diff --git a/source4/scripting/python/uuidmodule.c b/source4/scripting/python/uuidmodule.c new file mode 100644 index 0000000000..98ef9adaa9 --- /dev/null +++ b/source4/scripting/python/uuidmodule.c @@ -0,0 +1,58 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + 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/>. +*/ + +#include "includes.h" +#include <Python.h> +#include "librpc/ndr/libndr.h" + +static PyObject *uuid_random(PyObject *self, PyObject *args) +{ + struct GUID guid; + PyObject *pyobj; + char *str; + + if (!PyArg_ParseTuple(args, "")) + return NULL; + + guid = GUID_random(); + + str = GUID_string(NULL, &guid); + if (str == NULL) { + PyErr_SetString(PyExc_TypeError, "can't convert uuid to string"); + return NULL; + } + + pyobj = PyString_FromString(str); + + talloc_free(str); + + return pyobj; +} + +static PyMethodDef methods[] = { + { "uuid4", (PyCFunction)uuid_random, METH_VARARGS, NULL}, + { NULL, NULL } +}; + +void inituuid(void) +{ + PyObject *mod = Py_InitModule3("uuid", methods, "UUID helper routines"); + if (mod == NULL) + return; +} |