summaryrefslogtreecommitdiff
path: root/source4/scripting/python
diff options
context:
space:
mode:
Diffstat (limited to 'source4/scripting/python')
-rw-r--r--source4/scripting/python/config.mk35
-rw-r--r--source4/scripting/python/misc.i32
-rw-r--r--source4/scripting/python/parammodule.c182
-rw-r--r--source4/scripting/python/samba/__init__.py57
-rw-r--r--source4/scripting/python/samba/getopt.py46
-rw-r--r--source4/scripting/python/samba/samr.py753
-rwxr-xr-xsource4/scripting/python/samba/torture/pytorture51
-rw-r--r--source4/scripting/python/samba/torture/spoolss.py437
-rwxr-xr-xsource4/scripting/python/samba/torture/torture_samr.py221
-rwxr-xr-xsource4/scripting/python/samba/torture/torture_tdb.py90
-rwxr-xr-xsource4/scripting/python/samba/torture/winreg.py165
-rw-r--r--source4/scripting/python/sidmodule.c57
-rw-r--r--source4/scripting/python/uuidmodule.c57
13 files changed, 2183 insertions, 0 deletions
diff --git a/source4/scripting/python/config.mk b/source4/scripting/python/config.mk
new file mode 100644
index 0000000000..1c9ffb20ac
--- /dev/null
+++ b/source4/scripting/python/config.mk
@@ -0,0 +1,35 @@
+[PYTHON::python_param]
+PRIVATE_DEPENDENCIES = LIBSAMBA-CONFIG
+OBJ_FILES = parammodule.o
+
+[PYTHON::python_uuid]
+PRIVATE_DEPENDENCIES = LIBNDR
+OBJ_FILES = uuidmodule.o
+
+[PYTHON::python_sid]
+PRIVATE_DEPENDENCIES = LIBNDR
+OBJ_FILES = sidmodule.o
+
+[PYTHON::python_misc]
+PRIVATE_DEPENDENCIES = LIBNDR LIBLDB
+SWIG_FILE = misc.i
+
+# Swig extensions
+swig: pythonmods
+
+.SUFFIXES: _wrap.c .i
+
+.i_wrap.c:
+ swig -Wall -I$(srcdir)/scripting/swig -python $<
+
+clean::
+ @echo "Removing SWIG output files"
+ @-rm -f bin/python/*
+ # FIXME: Remove _wrap.c files
+ #
+pythonmods: $(PYTHON_DSOS)
+
+PYDOCTOR_MODULES=bin/python/ldb.py bin/python/auth.py bin/python/credentials.py bin/python/registry.py
+
+pydoctor:: pythonmods
+ LD_LIBRARY_PATH=bin/shared PYTHONPATH=bin/python pydoctor --make-html --docformat=restructuredtext --add-package scripting/python/samba/ $(addprefix --add-module , $(PYDOCTOR_MODULES))
diff --git a/source4/scripting/python/misc.i b/source4/scripting/python/misc.i
new file mode 100644
index 0000000000..088522320e
--- /dev/null
+++ b/source4/scripting/python/misc.i
@@ -0,0 +1,32 @@
+/*
+ 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(package="samba.misc") misc
+
+%{
+#include "includes.h"
+#include "ldb.h"
+#include "auth/credentials/credentials.h"
+%}
+
+%import "stdint.i"
+%import "../../lib/talloc/talloc.i"
+
+%rename(random_password) generate_random_str;
+char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len);
+
diff --git a/source4/scripting/python/parammodule.c b/source4/scripting/python/parammodule.c
new file mode 100644
index 0000000000..38d312cf1d
--- /dev/null
+++ b/source4/scripting/python/parammodule.c
@@ -0,0 +1,182 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Python wrapper for reading smb.conf files
+
+ Copyright (C) Jelmer Vernooij 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "scripting/python/talloc.h"
+#include "Python.h"
+#include "param/param.h"
+
+staticforward PyTypeObject param_ParamFileType;
+
+typedef struct {
+ PyObject_HEAD
+ struct param_context *param_ctx;
+} param_ParamFileObject;
+
+static param_ParamFileObject *py_param_init(void)
+{
+ param_ParamFileObject *param;
+
+ param = PyObject_New(param_ParamFileObject, &param_ParamFileType);
+
+ param->param_ctx = param_init(NULL);
+
+ return param;
+}
+
+static PyObject *py_param_load(PyObject *self, PyObject *args)
+{
+ char *filename = NULL;
+ param_ParamFileObject *param;
+
+ if (!PyArg_ParseTuple(args, "|s:new", &filename))
+ return NULL;
+
+ param = py_param_init();
+
+ if (filename != NULL) {
+ int ret = param_read(param->param_ctx, filename);
+
+ if (ret == -1) {
+ PyErr_SetString(PyExc_TypeError, "reading file failed");
+ return NULL;
+ }
+ }
+
+ return (PyObject *)param;
+}
+
+static void
+param_dealloc(PyObject* self)
+{
+ PyObject_Del(self);
+}
+
+static PyObject *py_param_get(PyObject *_self, PyObject *args)
+{
+ struct param_opt *param;
+ const char *section_name = NULL, *param_name = NULL;
+ param_ParamFileObject *self = (param_ParamFileObject *)_self;
+
+ if (!PyArg_ParseTuple(args, (char *)"s|s", &param_name, &section_name))
+ return NULL;
+
+ param = param_get(self->param_ctx, section_name, param_name);
+ if (param == NULL)
+ return Py_None;
+
+ return PyString_FromString(param->value);
+}
+
+static PyObject *py_param_set(PyObject *_self, PyObject *args)
+{
+ param_ParamFileObject *self = (param_ParamFileObject *)_self;
+ const char *section_name = NULL, *param_name = NULL, *param_value = NULL;
+
+ if (!PyArg_ParseTuple(args, "ss|s", &param_name, &param_value, &section_name))
+ return NULL;
+
+ if (section_name == NULL)
+ section_name = GLOBAL_NAME;
+
+ if (param_set_string(self->param_ctx, section_name, param_name, param_value) != 0) {
+ PyErr_SetString(PyExc_TypeError, "setting variable failed");
+ return NULL;
+ }
+
+ return Py_None;
+}
+
+static PyObject *py_param_save(PyObject *_self, PyObject *args)
+{
+ param_ParamFileObject *self = (param_ParamFileObject *)_self;
+ const char *filename = NULL;
+
+ if (!PyArg_ParseTuple(args, "s", &filename))
+ return NULL;
+
+ if (param_write(self->param_ctx, filename) != 0) {
+ PyErr_SetString(PyExc_TypeError, "unable to save");
+ return NULL;
+ }
+
+ return Py_None;
+}
+
+static PyObject *py_param_use(PyObject *_self, PyObject *args)
+{
+ param_ParamFileObject *self = (param_ParamFileObject *)_self;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ if (param_use(global_loadparm, self->param_ctx) != 0) {
+ PyErr_SetString(PyExc_TypeError, "unable to use");
+ return NULL;
+ }
+
+ return Py_None;
+}
+
+static PyMethodDef param_methods[] = {
+ {"get", (PyCFunction)py_param_get, METH_VARARGS,
+ "Get a parameter."},
+ {"set", (PyCFunction)py_param_set, METH_VARARGS,
+ "Set a parameter."},
+ {"save", (PyCFunction)py_param_save, METH_VARARGS,
+ "Save file" },
+ {"use", (PyCFunction)py_param_use, METH_VARARGS,
+ "Use param file" },
+ {NULL, NULL, 0, NULL}
+};
+
+static PyObject *
+param_getattr(PyTypeObject *obj, char *name)
+{
+ return Py_FindMethod(param_methods, (PyObject *)obj, name);
+}
+
+static PyTypeObject param_ParamFileType = {
+ PyObject_HEAD_INIT(NULL) 0,
+ .tp_name = "ParamFile",
+ .tp_basicsize = sizeof(param_ParamFileObject),
+ .tp_dealloc = param_dealloc,
+ .tp_getattr = param_getattr,
+};
+
+
+static PyMethodDef methods[] = {
+ { "ParamFile", (PyCFunction)py_param_load, METH_VARARGS, NULL},
+ { NULL, NULL }
+};
+
+PyDoc_STRVAR(param_doc, "Simple wrappers around the smb.conf parsers");
+
+PyMODINIT_FUNC initparam(void)
+{
+ PyObject *mod = Py_InitModule3("param", methods, param_doc);
+ if (mod == NULL)
+ return;
+
+ PyModule_AddObject(mod, "configfile",
+ PyString_FromString(lp_configfile(global_loadparm)));
+}
diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py
new file mode 100644
index 0000000000..46d8ff7d37
--- /dev/null
+++ b/source4/scripting/python/samba/__init__.py
@@ -0,0 +1,57 @@
+#!/usr/bin/python
+
+# Unix SMB/CIFS implementation.
+# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
+# 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 os
+from misc import ldb_set_credentials
+
+def Ldb(url, session_info=None, credentials=None, modules_dir=None):
+ """Open a Samba Ldb file.
+
+ 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).
+ """
+ import ldb
+ ret = ldb.Ldb()
+ if modules_dir is None:
+ modules_dir = os.path.join(os.getcwd(), "bin", "modules", "ldb")
+ ret.set_modules_dir(modules_dir)
+ def samba_debug(level,text):
+ print "%d %s" % (level, text)
+ ldb_set_opaque("credentials", credentials)
+ ret.set_opaque("sessionInfo", session_info)
+ #ret.set_debug(samba_debug)
+ ret.connect(url)
+ return ret
+
+
+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():
+ text = text.replace("${%s}" % name, value)
+
+ return text
+
diff --git a/source4/scripting/python/samba/getopt.py b/source4/scripting/python/samba/getopt.py
new file mode 100644
index 0000000000..8143dcafdb
--- /dev/null
+++ b/source4/scripting/python/samba/getopt.py
@@ -0,0 +1,46 @@
+#!/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/>.
+#
+
+import optparse
+from credentials import Credentials
+
+class SambaOptions(optparse.OptionGroup):
+ def __init__(self, parser):
+ optparse.OptionGroup.__init__(self, parser, "Samba Common Options")
+ self.add_option("--configfile", type="string", metavar="FILE",
+ help="Configuration file")
+
+
+class VersionOptions(optparse.OptionGroup):
+ def __init__(self, parser):
+ optparse.OptionGroup.__init__(self, parser, "Version Options")
+
+
+class CredentialsOptions(optparse.OptionGroup):
+ def __init__(self, parser):
+ optparse.OptionGroup.__init__(self, parser, "Credentials Options")
+ self.add_option("--simple-bind-dn", type="string", metavar="DN",
+ help="DN to use for a simple bind")
+ self.add_option("--password", type="string", metavar="PASSWORD",
+ help="Password")
+
+ def get_credentials(self):
+ creds = Credentials()
+ # FIXME: Update
+ return creds
diff --git a/source4/scripting/python/samba/samr.py b/source4/scripting/python/samba/samr.py
new file mode 100644
index 0000000000..314f78b8ad
--- /dev/null
+++ b/source4/scripting/python/samba/samr.py
@@ -0,0 +1,753 @@
+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:
+
+ 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/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/sidmodule.c b/source4/scripting/python/sidmodule.c
new file mode 100644
index 0000000000..2b3f152e9b
--- /dev/null
+++ b/source4/scripting/python/sidmodule.c
@@ -0,0 +1,57 @@
+/*
+ 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 "scripting/python/talloc.h"
+#include "Python.h"
+#include "libcli/security/security.h"
+
+static PyObject *sid_random(PyObject *self, PyObject *args)
+{
+ char *str;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ str = talloc_asprintf(NULL, "S-1-5-21-%u-%u-%u",
+ (unsigned)generate_random(),
+ (unsigned)generate_random(),
+ (unsigned)generate_random());
+
+ if (str == NULL) {
+ PyErr_SetString(PyExc_TypeError, "can't generate random sid");
+ return NULL;
+ }
+
+ return PyString_FromString(str);
+}
+
+static PyMethodDef methods[] = {
+ { "random", (PyCFunction)sid_random, METH_VARARGS, NULL},
+ { NULL, NULL }
+};
+
+PyDoc_STRVAR(param_doc, "SID helper routines");
+
+PyMODINIT_FUNC initsid(void)
+{
+ PyObject *mod = Py_InitModule3("sid", methods, param_doc);
+ if (mod == NULL)
+ return;
+}
diff --git a/source4/scripting/python/uuidmodule.c b/source4/scripting/python/uuidmodule.c
new file mode 100644
index 0000000000..9ae432dfa5
--- /dev/null
+++ b/source4/scripting/python/uuidmodule.c
@@ -0,0 +1,57 @@
+/*
+ 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;
+ 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;
+ }
+
+ talloc_free(str);
+
+ return PyString_FromString(str);
+}
+
+static PyMethodDef methods[] = {
+ { "random", (PyCFunction)uuid_random, METH_VARARGS, NULL},
+ { NULL, NULL }
+};
+
+PyDoc_STRVAR(param_doc, "UUID helper routines");
+
+PyMODINIT_FUNC inituuid(void)
+{
+ PyObject *mod = Py_InitModule3("uuid", methods, param_doc);
+ if (mod == NULL)
+ return;
+}