summaryrefslogtreecommitdiff
path: root/source4/python
diff options
context:
space:
mode:
Diffstat (limited to 'source4/python')
-rw-r--r--source4/python/.cvsignore1
-rw-r--r--source4/python/README28
-rwxr-xr-xsource4/python/examples/spoolss/changeid.py34
-rwxr-xr-xsource4/python/examples/spoolss/enumprinters.py36
-rwxr-xr-xsource4/python/examples/spoolss/psec.py88
-rw-r--r--source4/python/examples/tdbpack/.cvsignore2
-rw-r--r--source4/python/examples/tdbpack/oldtdbutil.py144
-rwxr-xr-xsource4/python/examples/tdbpack/tdbtimetrial.py12
-rwxr-xr-xsource4/python/examples/tdbpack/test_tdbpack.py253
-rwxr-xr-xsource4/python/gprinterdata39
-rwxr-xr-xsource4/python/gtdbtool39
-rwxr-xr-xsource4/python/gtkdictbrowser.py272
-rwxr-xr-xsource4/python/mkpatch6
-rw-r--r--source4/python/py_common.c259
-rw-r--r--source4/python/py_common.h67
-rw-r--r--source4/python/py_conv.c223
-rw-r--r--source4/python/py_conv.h44
-rw-r--r--source4/python/py_lsa.c468
-rw-r--r--source4/python/py_lsa.h41
-rw-r--r--source4/python/py_ntsec.c281
-rw-r--r--source4/python/py_samba.c56
-rw-r--r--source4/python/py_samr.c497
-rw-r--r--source4/python/py_samr.h81
-rw-r--r--source4/python/py_samr_conv.c58
-rw-r--r--source4/python/py_smb.c399
-rw-r--r--source4/python/py_smb.h39
-rw-r--r--source4/python/py_spoolss.c484
-rw-r--r--source4/python/py_spoolss.h160
-rw-r--r--source4/python/py_spoolss_common.c35
-rw-r--r--source4/python/py_spoolss_drivers.c421
-rw-r--r--source4/python/py_spoolss_drivers_conv.c179
-rw-r--r--source4/python/py_spoolss_forms.c266
-rw-r--r--source4/python/py_spoolss_forms_conv.c91
-rw-r--r--source4/python/py_spoolss_jobs.c377
-rw-r--r--source4/python/py_spoolss_jobs_conv.c102
-rw-r--r--source4/python/py_spoolss_ports.c137
-rw-r--r--source4/python/py_spoolss_ports_conv.c58
-rw-r--r--source4/python/py_spoolss_printerdata.c450
-rw-r--r--source4/python/py_spoolss_printers.c475
-rw-r--r--source4/python/py_spoolss_printers_conv.c354
-rw-r--r--source4/python/py_srvsvc.c215
-rw-r--r--source4/python/py_srvsvc.h26
-rw-r--r--source4/python/py_srvsvc_conv.c43
-rw-r--r--source4/python/py_tdb.c614
-rw-r--r--source4/python/py_tdb.h26
-rw-r--r--source4/python/py_tdbpack.c725
-rw-r--r--source4/python/py_winbind.c724
-rw-r--r--source4/python/py_winbind.h30
-rw-r--r--source4/python/py_winbind_conv.c41
-rw-r--r--source4/python/py_winreg.c82
-rw-r--r--source4/python/py_winreg.h29
-rw-r--r--source4/python/samba/.cvsignore1
-rw-r--r--source4/python/samba/__init__.py7
-rw-r--r--source4/python/samba/printerdata.py59
-rwxr-xr-xsource4/python/setup.py198
55 files changed, 9876 insertions, 0 deletions
diff --git a/source4/python/.cvsignore b/source4/python/.cvsignore
new file mode 100644
index 0000000000..7e99e367f8
--- /dev/null
+++ b/source4/python/.cvsignore
@@ -0,0 +1 @@
+*.pyc \ No newline at end of file
diff --git a/source4/python/README b/source4/python/README
new file mode 100644
index 0000000000..04f794215a
--- /dev/null
+++ b/source4/python/README
@@ -0,0 +1,28 @@
+This directory contains Python bindings to allow you to access various
+aspects of Samba. At the moment their status is "experimental" and
+they are not built by default.
+
+In order to be able to compile samba-python you need to have python
+and the python-dev packages installed.
+
+Python libraries are always built for a particular version of Python
+(2.2, 2.1, etc), and libraries built for one version will not be seen
+by another. By default Samba's libraries are built for whatever is
+installed as "python" on your $PATH, but you can override this using
+the --with-python option. For example
+
+ $ ./configure --with-python=python2.2
+
+To build:
+
+$ autoconf
+$ ./configure
+$ make python_ext
+
+Now, you can install the modules:
+
+$ cp build/lib.*/*.so /usr/lib/python2.1/lib-dynload/
+
+(the directory /usr/lib/python2.1 may vary, depending on your installation)
+
+Samba-python should work now!
diff --git a/source4/python/examples/spoolss/changeid.py b/source4/python/examples/spoolss/changeid.py
new file mode 100755
index 0000000000..85fe0efe8a
--- /dev/null
+++ b/source4/python/examples/spoolss/changeid.py
@@ -0,0 +1,34 @@
+#!/usr/bin/python
+#
+# Display the changeid for a list of printers given on the command line
+#
+# Sample usage:
+#
+# changeid.py '\\win2kdc1\magpie'
+#
+
+import sys
+from samba import spoolss
+
+if len(sys.argv) == 1:
+ print "Usage: changeid.py <printername>"
+ sys.exit(1)
+
+for printer in sys.argv[1:]:
+
+ # Open printer handle
+
+ try:
+ hnd = spoolss.openprinter(printer)
+ except:
+ print "error opening printer %s" % printer
+ sys.exit(1)
+
+ # Fetch and display changeid
+
+ info = hnd.getprinter(level = 0)
+ print info["change_id"]
+
+ # Clean up
+
+ spoolss.closeprinter(hnd)
diff --git a/source4/python/examples/spoolss/enumprinters.py b/source4/python/examples/spoolss/enumprinters.py
new file mode 100755
index 0000000000..478c46bc24
--- /dev/null
+++ b/source4/python/examples/spoolss/enumprinters.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+#
+# Display information on all printers on a print server. Defaults to
+# printer info level 1.
+#
+# Example: enumprinters.py win2kdc1
+#
+
+import sys
+from samba import spoolss
+
+if len(sys.argv) < 2 or len(sys.argv) > 3:
+ print "Usage: enumprinters.py <servername> [infolevel]"
+ sys.exit(1)
+
+printserver = sys.argv[1]
+
+level = 1
+if len(sys.argv) == 3:
+ level = int(sys.argv[2])
+
+# Get list of printers
+
+try:
+ printer_list = spoolss.enumprinters("\\\\%s" % printserver)
+except:
+ print "error enumerating printers on %s" % printserver
+ sys.exit(1)
+
+# Display basic info
+
+for printer in printer_list:
+ h = spoolss.openprinter("\\\\%s\\%s" % (printserver, printer))
+ info = h.getprinter(level = level)
+ print "Printer info %d for %s: %s" % (level, printer, info)
+ print
diff --git a/source4/python/examples/spoolss/psec.py b/source4/python/examples/spoolss/psec.py
new file mode 100755
index 0000000000..498a0ef174
--- /dev/null
+++ b/source4/python/examples/spoolss/psec.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python
+#
+# Get or set the security descriptor on a printer
+#
+
+import sys, re, string
+from samba import spoolss
+
+if len(sys.argv) != 3:
+ print "Usage: psec.py getsec|setsec printername"
+ sys.exit(1)
+
+op = sys.argv[1]
+printername = sys.argv[2]
+
+# Display security descriptor
+
+if op == "getsec":
+
+ try:
+ hnd = spoolss.openprinter(printername)
+ except:
+ print "error opening printer %s" % printername
+ sys.exit(1)
+
+ secdesc = hnd.getprinter(level = 3)["security_descriptor"]
+
+ print secdesc["owner_sid"]
+ print secdesc["group_sid"]
+
+ for acl in secdesc["dacl"]["ace_list"]:
+ print "%d %d 0x%08x %s" % (acl["type"], acl["flags"],
+ acl["mask"], acl["trustee"])
+
+ spoolss.closeprinter(hnd)
+
+ sys.exit(0)
+
+# Set security descriptor
+
+if op == "setsec":
+
+ # Open printer
+
+ try:
+ hnd = spoolss.openprinter(printername,
+ creds = {"domain": "NPSD-TEST2",
+ "username": "Administrator",
+ "password": "penguin"})
+ except:
+ print "error opening printer %s" % printername
+ sys.exit(1)
+
+ # Read lines from standard input and build security descriptor
+
+ lines = sys.stdin.readlines()
+
+ secdesc = {}
+
+ secdesc["owner_sid"] = lines[0]
+ secdesc["group_sid"] = lines[1]
+
+ secdesc["revision"] = 1
+ secdesc["dacl"] = {}
+ secdesc["dacl"]["revision"] = 2
+ secdesc["dacl"]["ace_list"] = []
+
+ for acl in lines[2:]:
+ match = re.match("(\d+) (\d+) (0[xX][\dA-Fa-f]+) (\S+)", acl)
+ secdesc["dacl"]["ace_list"].append(
+ {"type": int(match.group(1)), "flags": int(match.group(2)),
+ "mask": string.atoi(match.group(3), 0), "trustee": match.group(4)})
+
+ # Build info3 structure
+
+ info3 = {}
+
+ info3["flags"] = 0x8004 # self-relative, dacl present
+ info3["level"] = 3
+ info3["security_descriptor"] = secdesc
+
+ hnd.setprinter(info3)
+
+ spoolss.closeprinter(hnd)
+ sys.exit(0)
+
+print "invalid operation %s" % op
+sys.exit(1)
diff --git a/source4/python/examples/tdbpack/.cvsignore b/source4/python/examples/tdbpack/.cvsignore
new file mode 100644
index 0000000000..52e4e61140
--- /dev/null
+++ b/source4/python/examples/tdbpack/.cvsignore
@@ -0,0 +1,2 @@
+*.pyc
+*.pyo
diff --git a/source4/python/examples/tdbpack/oldtdbutil.py b/source4/python/examples/tdbpack/oldtdbutil.py
new file mode 100644
index 0000000000..ac435b8bac
--- /dev/null
+++ b/source4/python/examples/tdbpack/oldtdbutil.py
@@ -0,0 +1,144 @@
+#!/usr/bin/python
+#############################################################
+# tdbutil
+#
+# Purpose:
+# Contains functions that are used to pack and unpack data
+# from Samba's tdb databases. Samba sometimes represents complex
+# data structures as a single value in a database. These functions
+# allow other python scripts to package data types into a single python
+# string and unpackage them.
+#
+#
+# XXXXX: This code is no longer used; it's just here for testing
+# compatibility with the new (much faster) C implementation.
+#
+##############################################################
+import string
+
+def pack(format,list):
+ retstring = ''
+ listind = 0
+
+ # Cycle through format entries
+ for type in format:
+ # Null Terminated String
+ if (type == 'f' or type == 'P'):
+ retstring = retstring + list[listind] + "\000"
+ # 4 Byte Number
+ if (type == 'd'):
+ retstring = retstring + PackNum(list[listind],4)
+ # 2 Byte Number
+ if (type == 'w'):
+ retstring = retstring + PackNum(list[listind],2)
+ # Pointer Value
+ if (type == 'p'):
+ if (list[listind]):
+ retstring = retstring + PackNum(1,4)
+ else:
+ retstring = retstring + PackNum(0,4)
+ # Buffer and Length
+ if (type == 'B'):
+ # length
+ length = list[listind]
+ retstring = retstring + PackNum(length,4)
+ length = int(length)
+ listind = listind + 1
+ # buffer
+ retstring = retstring + list[listind][:length]
+
+ listind = listind + 1
+
+ return retstring
+
+def unpack(format,buffer):
+ retlist = []
+ bufind = 0
+
+ lasttype = ""
+ for type in format:
+ # Pointer Value
+ if (type == 'p'):
+ newvalue = UnpackNum(buffer[bufind:bufind+4])
+ bufind = bufind + 4
+ if (newvalue):
+ newvalue = 1L
+ else:
+ newvalue = 0L
+ retlist.append(newvalue)
+ # Previous character till end of data
+ elif (type == '$'):
+ if (lasttype == 'f'):
+ while (bufind < len(buffer)):
+ newstring = ''
+ while (buffer[bufind] != '\000'):
+ newstring = newstring + buffer[bufind]
+ bufind = bufind + 1
+ bufind = bufind + 1
+ retlist.append(newstring)
+ # Null Terminated String
+ elif (type == 'f' or type == 'P'):
+ newstring = ''
+ while (buffer[bufind] != '\000'):
+ newstring = newstring + buffer[bufind]
+ bufind = bufind + 1
+ bufind = bufind + 1
+ retlist.append(newstring)
+ # 4 Byte Number
+ elif (type == 'd'):
+ newvalue = UnpackNum(buffer[bufind:bufind+4])
+ bufind = bufind + 4
+ retlist.append(newvalue)
+ # 2 Byte Number
+ elif (type == 'w'):
+ newvalue = UnpackNum(buffer[bufind:bufind+2])
+ bufind = bufind + 2
+ retlist.append(newvalue)
+ # Length and Buffer
+ elif (type == 'B'):
+ # Length
+ length = UnpackNum(buffer[bufind:bufind+4])
+ bufind = bufind + 4
+ retlist.append(length)
+ length = int(length)
+ # Buffer
+ retlist.append(buffer[bufind:bufind+length])
+ bufind = bufind + length
+
+ lasttype = type
+
+ return ((retlist,buffer[bufind:]))
+
+def PackNum(myint,size):
+ retstring = ''
+ size = size * 2
+ hint = hex(myint)[2:]
+
+ # Check for long notation
+ if (hint[-1:] == 'L'):
+ hint = hint[:-1]
+
+ addon = size - len(hint)
+ for i in range(0,addon):
+ hint = '0' + hint
+
+ while (size > 0):
+ val = string.atoi(hint[size-2:size],16)
+ retstring = retstring + chr(val)
+ size = size - 2
+
+ return retstring
+
+def UnpackNum(buffer):
+ size = len(buffer)
+ mystring = ''
+
+ for i in range(size-1,-1,-1):
+ val = hex(ord(buffer[i]))[2:]
+ if (len(val) == 1):
+ val = '0' + val
+ mystring = mystring + val
+ if (len(mystring) > 4):
+ return string.atol(mystring,16)
+ else:
+ return string.atoi(mystring,16)
diff --git a/source4/python/examples/tdbpack/tdbtimetrial.py b/source4/python/examples/tdbpack/tdbtimetrial.py
new file mode 100755
index 0000000000..be6404899d
--- /dev/null
+++ b/source4/python/examples/tdbpack/tdbtimetrial.py
@@ -0,0 +1,12 @@
+#! /usr/bin/python2.2
+
+def run_trial():
+ # import tdbutil
+ from samba.tdbpack import pack
+
+ for i in xrange(500000):
+ pack("ddffd", (10, 2, "mbp", "martin", 0))
+ #s = "\n\0\0\0" + "\x02\0\0\0" + "mbp\0" + "martin\0" + "\0\0\0\0"
+
+if __name__ == '__main__':
+ run_trial()
diff --git a/source4/python/examples/tdbpack/test_tdbpack.py b/source4/python/examples/tdbpack/test_tdbpack.py
new file mode 100755
index 0000000000..837600f789
--- /dev/null
+++ b/source4/python/examples/tdbpack/test_tdbpack.py
@@ -0,0 +1,253 @@
+#! /usr/bin/env python2.2
+
+__doc__ = """test case for samba.tdbpack functions
+
+tdbpack provides a means of pickling values into binary formats
+compatible with that used by the samba tdbpack()/tdbunpack()
+functions.
+
+Numbers are always stored in little-endian format; strings are stored
+in either DOS or Unix codepage as appropriate.
+
+The format for any particular element is encoded as a short ASCII
+string, with one character per field."""
+
+# Copyright (C) 2002 Hewlett-Packard.
+
+__author__ = 'Martin Pool <mbp@sourcefrog.net>'
+
+import unittest
+import oldtdbutil
+import samba.tdbpack
+
+both_unpackers = (samba.tdbpack.unpack, oldtdbutil.unpack)
+both_packers = (samba.tdbpack.pack, oldtdbutil.pack)
+
+
+
+# # ('B', [10, 'hello'], '\x0a\0\0\0hello'),
+# ('BB', [11, 'hello\0world', 3, 'now'],
+# '\x0b\0\0\0hello\0world\x03\0\0\0now'),
+# ('pd', [1, 10], '\x01\0\0\0\x0a\0\0\0'),
+# ('BBB', [5, 'hello', 0, '', 5, 'world'],
+# '\x05\0\0\0hello\0\0\0\0\x05\0\0\0world'),
+
+ # strings are sequences in Python, there's no getting away
+ # from it
+# ('ffff', 'evil', 'e\0v\0i\0l\0'),
+# ('BBBB', 'evil',
+# '\x01\0\0\0e'
+# '\x01\0\0\0v'
+# '\x01\0\0\0i'
+# '\x01\0\0\0l'),
+
+# ('', [], ''),
+
+# # exercise some long strings
+# ('PP', ['hello' * 255, 'world' * 255],
+# 'hello' * 255 + '\0' + 'world' * 255 + '\0'),
+# ('PP', ['hello' * 40000, 'world' * 50000],
+# 'hello' * 40000 + '\0' + 'world' * 50000 + '\0'),
+# ('B', [(5*51), 'hello' * 51], '\xff\0\0\0' + 'hello' * 51),
+# ('BB', [(5 * 40000), 'hello' * 40000,
+# (5 * 50000), 'world' * 50000],
+# '\x40\x0d\x03\0' + 'hello' * 40000 + '\x90\xd0\x03\x00' + 'world' * 50000),
+
+
+class PackTests(unittest.TestCase):
+ symm_cases = [
+ ('w', [42], '\x2a\0'),
+ ('www', [42, 2, 69], '\x2a\0\x02\0\x45\0'),
+ ('wd', [42, 256], '\x2a\0\0\x01\0\0'),
+ ('w', [0], '\0\0'),
+ ('w', [255], '\xff\0'),
+ ('w', [256], '\0\x01'),
+ ('w', [0xdead], '\xad\xde'),
+ ('w', [0xffff], '\xff\xff'),
+ ('p', [0], '\0\0\0\0'),
+ ('p', [1], '\x01\0\0\0'),
+ ('d', [0x01020304], '\x04\x03\x02\x01'),
+ ('d', [0x7fffffff], '\xff\xff\xff\x7f'),
+ ('d', [0x80000000L], '\x00\x00\x00\x80'),
+ ('d', [0x80000069L], '\x69\x00\x00\x80'),
+ ('d', [0xffffffffL], '\xff\xff\xff\xff'),
+ ('d', [0xffffff00L], '\x00\xff\xff\xff'),
+ ('ddd', [1, 10, 50], '\x01\0\0\0\x0a\0\0\0\x32\0\0\0'),
+ ('ff', ['hello', 'world'], 'hello\0world\0'),
+ ('fP', ['hello', 'world'], 'hello\0world\0'),
+ ('PP', ['hello', 'world'], 'hello\0world\0'),
+ ('B', [0, ''], '\0\0\0\0'),
+# old implementation is wierd when string is not the right length
+# ('B', [2, 'hello'], '\x0a\0\0\0hello'),
+ ('B', [5, 'hello'], '\x05\0\0\0hello'),
+ ]
+
+ def test_symmetric(self):
+ """Cookbook of symmetric pack/unpack tests
+ """
+ for packer in [samba.tdbpack.pack]: # both_packers:
+ for unpacker in both_unpackers:
+ for format, values, expected in self.symm_cases:
+ out_packed = packer(format, values)
+ self.assertEquals(out_packed, expected)
+ out, rest = unpacker(format, expected)
+ self.assertEquals(rest, '')
+ self.assertEquals(list(values), list(out))
+
+ def test_large(self):
+ """Test large pack/unpack strings"""
+ large_cases = [('w' * 1000, xrange(1000)), ]
+ for packer in both_packers:
+ for unpacker in both_unpackers:
+ for format, values in large_cases:
+ packed = packer(format, values)
+ out, rest = unpacker(format, packed)
+ self.assertEquals(rest, '')
+ self.assertEquals(list(values), list(out))
+
+
+ def test_pack(self):
+ """Cookbook of expected pack values
+
+ These can't be used for the symmetric test because the unpacked value is
+ not "canonical".
+ """
+ cases = [('w', (42,), '\x2a\0'),
+ ]
+
+ for packer in both_packers:
+ for format, values, expected in cases:
+ self.assertEquals(packer(format, values), expected)
+
+ def test_unpack_extra(self):
+ # Test leftover data
+ for unpacker in both_unpackers:
+ for format, values, packed in self.symm_cases:
+ out, rest = unpacker(format, packed + 'hello sailor!')
+ self.assertEquals(rest, 'hello sailor!')
+ self.assertEquals(list(values), list(out))
+
+
+ def test_pack_extra(self):
+ """Leftover values when packing"""
+ cases = [
+ ('d', [10, 20], [10]),
+ ('d', [10, 'hello'], [10]),
+ ('ff', ['hello', 'world', 'sailor'], ['hello', 'world']),
+ ]
+ for unpacker in both_unpackers:
+ for packer in both_packers:
+ for format, values, chopped in cases:
+ bin = packer(format, values)
+ out, rest = unpacker(format, bin)
+ self.assertEquals(list(out), list(chopped))
+ self.assertEquals(rest, '')
+
+
+ def test_unpack(self):
+ """Cookbook of tricky unpack tests"""
+ cases = [
+ # Apparently I couldn't think of any tests that weren't
+ # symmetric :-/
+ ]
+ for unpacker in both_unpackers:
+ for format, values, expected in cases:
+ out, rest = unpacker(format, expected)
+ self.assertEquals(rest, '')
+ self.assertEquals(list(values), list(out))
+
+
+ def test_pack_failures(self):
+ """Expected errors for incorrect packing"""
+ cases = [('w', []),
+# ('w', ()),
+# ('w', {}),
+ ('ww', [2]),
+ ('w', 2),
+# ('w', None),
+ ('wwwwwwwwwwww', []),
+# ('w', [0x60A15EC5L]),
+# ('w', [None]),
+ ('d', []),
+ ('p', []),
+ ('f', [2]),
+ ('P', [None]),
+ ('P', ()),
+ ('f', [hex]),
+ ('fw', ['hello']),
+# ('f', [u'hello']),
+ ('B', [2]),
+ (None, [2, 3, 4]),
+ (ord('f'), [20]),
+ # old code doesn't distinguish string from seq-of-char
+# (['w', 'w'], [2, 2]),
+ # old code just ignores invalid characters
+# ('Q', [2]),
+# ('fQ', ['2', 3]),
+# ('fQ', ['2']),
+ (2, [2]),
+ # old code doesn't typecheck format
+# ({}, {})
+ ]
+ for packer in both_packers:
+ for format, values in cases:
+ try:
+ packer(format, values)
+ except StandardError:
+ pass
+ else:
+ raise AssertionError("didn't get exception: format %s, values %s, packer %s"
+ % (`format`, `values`, `packer`))
+
+
+ def test_unpack_failures(self):
+ """Expected errors for incorrect unpacking"""
+ cases = [
+# This ought to be illegal, but the old code doesn't prohibit it
+# ('$', '', ValueError),
+# ('Q', '', ValueError),
+# ('Q$', '', ValueError),
+ ('f', '', IndexError),
+ ('d', '', IndexError),
+# This is an illegal packing, but the old code doesn't trap
+# ('d', '2', IndexError),
+# ('d', '22', IndexError),
+# ('d', '222', IndexError),
+# ('p', '\x01\0', IndexError),
+# ('w', '2', IndexError),
+# ('B', '\xff\0\0\0hello', IndexError),
+# ('B', '\xff\0', IndexError),
+ ('w', '', IndexError),
+ ('f', 'hello', IndexError),
+ ('f', '', IndexError),
+# ('B', '\x01\0\0\0', IndexError),
+# ('B', '\x05\0\0\0hell', IndexError),
+ ('B', '\xff\xff\xff\xff', ValueError),
+# ('B', 'foobar', IndexError),
+# ('BB', '\x01\0\0\0a\x01', IndexError),
+ ]
+
+ for unpacker in both_unpackers:
+ for format, values, throwable_class in cases:
+ try:
+ unpacker(format, values)
+ except StandardError:
+ pass
+ else:
+ raise AssertionError("didn't get exception: format %s, values %s, unpacker %s"
+ % (`format`, `values`, `unpacker`))
+
+ def test_unpack_repeated(self):
+ cases = [(('df$',
+ '\x00\x00\x00\x00HP C LaserJet 4500-PS\x00Windows 4.0\x00\\print$\\WIN40\\0\\PSCRIPT.DRV\x00\\print$\\WIN40\\0\\PSCRIPT.DRV\x00\\print$\\WIN40\\0\\PSCRIPT.DRV\x00\\print$\\WIN40\\0\\PSCRIPT.HLP\x00\x00RAW\x00\\print$\\WIN40\\0\\readme.wri\x00\\print$\\WIN40\\0\\pscript.drv\x00\\print$\\WIN40\\0\\pscript.hlp\x00'),
+ ([0L, 'HP C LaserJet 4500-PS', 'Windows 4.0', '\\print$\\WIN40\\0\\PSCRIPT.DRV', '\\print$\\WIN40\\0\\PSCRIPT.DRV', '\\print$\\WIN40\\0\\PSCRIPT.DRV', '\\print$\\WIN40\\0\\PSCRIPT.HLP', '', 'RAW', '\\print$\\WIN40\\0\\readme.wri', '\\print$\\WIN40\\0\\pscript.drv', '\\print$\\WIN40\\0\\pscript.hlp'], ''))]
+ for unpacker in both_unpackers:
+ for input, expected in cases:
+ result = apply(unpacker, input)
+ if result != expected:
+ raise AssertionError("%s:\n input: %s\n output: %s\n expected: %s" % (`unpacker`, `input`, `result`, `expected`))
+
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/source4/python/gprinterdata b/source4/python/gprinterdata
new file mode 100755
index 0000000000..cd062076c0
--- /dev/null
+++ b/source4/python/gprinterdata
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+
+import sys
+from gtkdictbrowser import GtkDictBrowser, hex_string
+import gtk
+from samba import spoolss
+import string
+import printerdata
+
+# Initialise printerdata dictionary
+
+if len(sys.argv) < 2 or len(sys.argv) > 3:
+ print "Usage: gprinterdata [--ex] <printer>"
+ print "where <printer> is a UNC printer name."
+ sys.exit(1)
+
+try:
+ host = string.replace(sys.argv[len(sys.argv) - 1], "/", "\\")
+ if sys.argv[1] == "--ex":
+ t = printerdata.printerdata_ex(host)
+ else:
+ t = printerdata.printerdata(host)
+except:
+ print "gprinterdata: error opening %s" % sys.argv[len(sys.argv) - 1]
+ sys.exit(1)
+
+# Create interface
+
+db = GtkDictBrowser(t)
+db.register_get_value_text_fn("", hex_string)
+db.build_ui('gprinterdata')
+
+# Override Python's handling of ctrl-c so we can break out of the
+# gui from the command line.
+
+import signal
+signal.signal(signal.SIGINT, signal.SIG_DFL)
+
+gtk.mainloop()
diff --git a/source4/python/gtdbtool b/source4/python/gtdbtool
new file mode 100755
index 0000000000..129f4fe0e2
--- /dev/null
+++ b/source4/python/gtdbtool
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+
+import sys
+from gtkdictbrowser import GtkDictBrowser
+import gtk
+from samba import tdb
+import string
+
+# Open handle on tdb
+
+if len(sys.argv) != 2:
+ print "Usage: gdbtool <tdbfile>"
+ sys.exit(1)
+
+try:
+ t = tdb.open(sys.argv[1])
+except tdb.error, t:
+ print "gtdbtool: error opening %s: %s" % (sys.argv[1], t)
+ sys.exit(1)
+
+# Create interface
+
+db = GtkDictBrowser(t)
+
+def display_key_x00(key):
+ """Remove \x00 from all keys as they mucks up GTK."""
+ return string.replace(key, "\x00", "")
+
+db.register_get_key_text_fn(display_key_x00)
+
+db.build_ui('gtdbtool')
+
+# Override Python's handling of ctrl-c so we can break out of the
+# gui from the command line.
+
+import signal
+signal.signal(signal.SIGINT, signal.SIG_DFL)
+
+gtk.mainloop()
diff --git a/source4/python/gtkdictbrowser.py b/source4/python/gtkdictbrowser.py
new file mode 100755
index 0000000000..dd8bed8f47
--- /dev/null
+++ b/source4/python/gtkdictbrowser.py
@@ -0,0 +1,272 @@
+#!/usr/bin/python
+#
+# Browse a Python dictionary in a two pane graphical interface written
+# in GTK.
+#
+# The GtkDictBrowser class is supposed to be generic enough to allow
+# applications to override enough methods and produce a
+# domain-specific browser provided the information is presented as a
+# Python dictionary.
+#
+# Possible applications:
+#
+# - Windows registry browser
+# - SPOOLSS printerdata browser
+# - tdb file browser
+#
+
+from gtk import *
+import string, re
+
+class GtkDictBrowser:
+
+ def __init__(self, dict):
+ self.dict = dict
+
+ # This variable stores a list of (regexp, function) used to
+ # convert the raw value data to a displayable string.
+
+ self.get_value_text_fns = []
+ self.get_key_text = lambda x: x
+
+ # We can filter the list of keys displayed using a regex
+
+ self.filter_regex = ""
+
+ # Create and configure user interface widgets. A string argument is
+ # used to set the window title.
+
+ def build_ui(self, title):
+ win = GtkWindow()
+ win.set_title(title)
+
+ win.connect("destroy", mainquit)
+
+ hpaned = GtkHPaned()
+ win.add(hpaned)
+ hpaned.set_border_width(5)
+ hpaned.show()
+
+ vbox = GtkVBox()
+ hpaned.add1(vbox)
+ vbox.show()
+
+ scrolled_win = GtkScrolledWindow()
+ scrolled_win.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
+ vbox.pack_start(scrolled_win)
+ scrolled_win.show()
+
+ hbox = GtkHBox()
+ vbox.pack_end(hbox, expand = 0, padding = 5)
+ hbox.show()
+
+ label = GtkLabel("Filter:")
+ hbox.pack_start(label, expand = 0, padding = 5)
+ label.show()
+
+ self.entry = GtkEntry()
+ hbox.pack_end(self.entry, padding = 5)
+ self.entry.show()
+
+ self.entry.connect("activate", self.filter_activated)
+
+ self.list = GtkList()
+ self.list.set_selection_mode(SELECTION_MULTIPLE)
+ self.list.set_selection_mode(SELECTION_BROWSE)
+ scrolled_win.add_with_viewport(self.list)
+ self.list.show()
+
+ self.list.connect("select_child", self.key_selected)
+
+ scrolled_win = GtkScrolledWindow()
+ scrolled_win.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
+ hpaned.add2(scrolled_win)
+ scrolled_win.set_usize(500,400)
+ scrolled_win.show()
+
+ self.text = GtkText()
+ self.text.set_editable(FALSE)
+ scrolled_win.add_with_viewport(self.text)
+ self.text.show()
+
+ self.text.connect("event", self.event_handler)
+
+ self.menu = GtkMenu()
+ self.menu.show()
+
+ self.font = load_font("fixed")
+
+ self.update_keylist()
+
+ win.show()
+
+ # Add a key to the left hand side of the user interface
+
+ def add_key(self, key):
+ display_key = self.get_key_text(key)
+ list_item = GtkListItem(display_key)
+ list_item.set_data("raw_key", key) # Store raw key in item data
+ self.list.add(list_item)
+ list_item.show()
+
+ # Event handler registered by build_ui()
+
+ def event_handler(self, event, menu):
+ return FALSE
+
+ # Set the text to appear in the right hand side of the user interface
+
+ def set_value_text(self, item):
+
+ # Clear old old value in text window
+
+ self.text.delete_text(0, self.text.get_length())
+
+ if type(item) == str:
+
+ # The text widget has trouble inserting text containing NULL
+ # characters.
+
+ item = string.replace(item, "\x00", ".")
+
+ self.text.insert(self.font, None, None, item)
+
+ else:
+
+ # A non-text item
+
+ self.text.insert(self.font, None, None, repr(item))
+
+ # This function is called when a key is selected in the left hand side
+ # of the user interface.
+
+ def key_selected(self, list, list_item):
+ key = list_item.children()[0].get()
+
+ # Look for a match in the value display function list
+
+ text = self.dict[list_item.get_data("raw_key")]
+
+ for entry in self.get_value_text_fns:
+ if re.match(entry[0], key):
+ text = entry[1](text)
+ break
+
+ self.set_value_text(text)
+
+ # Refresh the key list by removing all items and re-inserting them.
+ # Items are only inserted if they pass through the filter regexp.
+
+ def update_keylist(self):
+ self.list.remove_items(self.list.children())
+ self.set_value_text("")
+ for k in self.dict.keys():
+ if re.match(self.filter_regex, k):
+ self.add_key(k)
+
+ # Invoked when the user hits return in the filter text entry widget.
+
+ def filter_activated(self, entry):
+ self.filter_regex = entry.get_text()
+ self.update_keylist()
+
+ # Register a key display function
+
+ def register_get_key_text_fn(self, fn):
+ self.get_key_text = fn
+
+ # Register a value display function
+
+ def register_get_value_text_fn(self, regexp, fn):
+ self.get_value_text_fns.append((regexp, fn))
+
+#
+# A utility function to convert a string to the standard hex + ascii format.
+# To display all values in hex do:
+# register_get_value_text_fn("", gtkdictbrowser.hex_string)
+#
+
+def hex_string(data):
+ """Return a hex dump of a string as a string.
+
+ The output produced is in the standard 16 characters per line hex +
+ ascii format:
+
+ 00000000: 40 00 00 00 00 00 00 00 40 00 00 00 01 00 04 80 @....... @.......
+ 00000010: 01 01 00 00 00 00 00 01 00 00 00 00 ........ ....
+ """
+
+ pos = 0 # Position in data
+ line = 0 # Line of data
+
+ hex = "" # Hex display
+ ascii = "" # ASCII display
+
+ result = ""
+
+ while pos < len(data):
+
+ # Start with header
+
+ if pos % 16 == 0:
+ hex = "%08x: " % (line * 16)
+ ascii = ""
+
+ # Add character
+
+ hex = hex + "%02x " % (ord(data[pos]))
+
+ if ord(data[pos]) < 32 or ord(data[pos]) > 176:
+ ascii = ascii + '.'
+ else:
+ ascii = ascii + data[pos]
+
+ pos = pos + 1
+
+ # Add separator if half way
+
+ if pos % 16 == 8:
+ hex = hex + " "
+ ascii = ascii + " "
+
+ # End of line
+
+ if pos % 16 == 0:
+ result = result + "%s %s\n" % (hex, ascii)
+ line = line + 1
+
+ # Leftover bits
+
+ if pos % 16 != 0:
+
+ # Pad hex string
+
+ for i in range(0, (16 - (pos % 16))):
+ hex = hex + " "
+
+ # Half way separator
+
+ if (pos % 16) < 8:
+ hex = hex + " "
+
+ result = result + "%s %s\n" % (hex, ascii)
+
+ return result
+
+# For testing purposes, create a fixed dictionary to browse with
+
+if __name__ == "__main__":
+
+ dict = {"chicken": "ham", "spam": "fun", "subdict": {"a": "b", "c": "d"}}
+
+ db = GtkDictBrowser(dict)
+
+ db.build_ui("GtkDictBrowser")
+
+ # Override Python's handling of ctrl-c so we can break out of the
+ # gui from the command line.
+
+ import signal
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
+
+ mainloop()
diff --git a/source4/python/mkpatch b/source4/python/mkpatch
new file mode 100755
index 0000000000..ab5be1b6a2
--- /dev/null
+++ b/source4/python/mkpatch
@@ -0,0 +1,6 @@
+#!/bin/sh
+#
+# Make samba-head.patch. Must be run from samba source directory.
+#
+
+cvs -z3 diff -u Makefile.in configure.in > python/samba-head.patch
diff --git a/source4/python/py_common.c b/source4/python/py_common.c
new file mode 100644
index 0000000000..ea092d9370
--- /dev/null
+++ b/source4/python/py_common.c
@@ -0,0 +1,259 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_common.h"
+
+/* Return a tuple of (error code, error string) from a WERROR */
+
+PyObject *py_werror_tuple(WERROR werror)
+{
+ return Py_BuildValue("[is]", W_ERROR_V(werror),
+ dos_errstr(werror));
+}
+
+/* Return a tuple of (error code, error string) from a WERROR */
+
+PyObject *py_ntstatus_tuple(NTSTATUS ntstatus)
+{
+ return Py_BuildValue("[is]", NT_STATUS_V(ntstatus),
+ nt_errstr(ntstatus));
+}
+
+/* Initialise samba client routines */
+
+static BOOL initialised;
+
+void py_samba_init(void)
+{
+ if (initialised)
+ return;
+
+ /* Load configuration file */
+
+ if (!lp_load(dyn_CONFIGFILE, True, False, False))
+ fprintf(stderr, "Can't load %s\n", dyn_CONFIGFILE);
+
+ /* Misc other stuff */
+
+ load_interfaces();
+ init_names();
+
+ initialised = True;
+}
+
+/* Debuglevel routines */
+
+PyObject *get_debuglevel(PyObject *self, PyObject *args)
+{
+ PyObject *debuglevel;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ debuglevel = PyInt_FromLong(DEBUGLEVEL);
+
+ return debuglevel;
+}
+
+PyObject *set_debuglevel(PyObject *self, PyObject *args)
+{
+ int debuglevel;
+
+ if (!PyArg_ParseTuple(args, "i", &debuglevel))
+ return NULL;
+
+ DEBUGLEVEL = debuglevel;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Initialise logging */
+
+PyObject *py_setup_logging(PyObject *self, PyObject *args, PyObject *kw)
+{
+ BOOL interactive = False;
+ char *logfilename = NULL;
+ static char *kwlist[] = {"interactive", "logfilename", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "|is", kwlist, &interactive, &logfilename))
+ return NULL;
+
+ if (interactive && logfilename) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "can't be interactive and set log file name");
+ return NULL;
+ }
+
+ if (interactive)
+ setup_logging("spoolss", True);
+
+ if (logfilename) {
+ lp_set_logfile(logfilename);
+ setup_logging(logfilename, False);
+ reopen_logs();
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Parse credentials from a python dictionary. The dictionary can
+ only have the keys "username", "domain" and "password". Return
+ True for valid credentials in which case the username, domain and
+ password are set to pointers to their values from the dicationary.
+ If returns False, the errstr is set to point at some mallocated
+ memory describing the error. */
+
+BOOL py_parse_creds(PyObject *creds, char **username, char **domain,
+ char **password, char **errstr)
+{
+ /* Initialise anonymous credentials */
+
+ *username = "";
+ *domain = "";
+ *password = "";
+
+ if (creds && PyDict_Size(creds) > 0) {
+ PyObject *username_obj, *password_obj, *domain_obj;
+ PyObject *key, *value;
+ int i;
+
+ /* Check for presence of required fields */
+
+ username_obj = PyDict_GetItemString(creds, "username");
+ domain_obj = PyDict_GetItemString(creds, "domain");
+ password_obj = PyDict_GetItemString(creds, "password");
+
+ if (!username_obj) {
+ *errstr = strdup("no username field in credential");
+ return False;
+ }
+
+ if (!domain_obj) {
+ *errstr = strdup("no domain field in credential");
+ return False;
+ }
+
+ if (!password_obj) {
+ *errstr = strdup("no password field in credential");
+ return False;
+ }
+
+ /* Check type of required fields */
+
+ if (!PyString_Check(username_obj)) {
+ *errstr = strdup("username field is not string type");
+ return False;
+ }
+
+ if (!PyString_Check(domain_obj)) {
+ *errstr = strdup("domain field is not string type");
+ return False;
+ }
+
+ if (!PyString_Check(password_obj)) {
+ *errstr = strdup("password field is not string type");
+ return False;
+ }
+
+ /* Look for any extra fields */
+
+ i = 0;
+
+ while (PyDict_Next(creds, &i, &key, &value)) {
+ if (strcmp(PyString_AsString(key), "domain") != 0 &&
+ strcmp(PyString_AsString(key), "username") != 0 &&
+ strcmp(PyString_AsString(key), "password") != 0) {
+ asprintf(errstr,
+ "creds contain extra field '%s'",
+ PyString_AsString(key));
+ return False;
+ }
+ }
+
+ /* Assign values */
+
+ *username = PyString_AsString(username_obj);
+ *domain = PyString_AsString(domain_obj);
+ *password = PyString_AsString(password_obj);
+ }
+
+ *errstr = NULL;
+
+ return True;
+}
+
+/* Return a cli_state to a RPC pipe on the given server. Use the
+ credentials passed if not NULL. If an error occurs errstr is set to a
+ string describing the error and NULL is returned. If set, errstr must
+ be freed by calling free(). */
+
+struct cli_state *open_pipe_creds(char *server, PyObject *creds,
+ int pipe_idx, char **errstr)
+{
+ char *username, *password, *domain;
+ struct cli_state *cli;
+ NTSTATUS result;
+
+ /* Extract credentials from the python dictionary */
+
+ if (!py_parse_creds(creds, &username, &domain, &password, errstr))
+ return NULL;
+
+ /* Now try to connect */
+
+ result = cli_full_connection(
+ &cli, NULL, server, NULL, 0, "IPC$", "IPC",
+ username, domain, password, 0, NULL);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ *errstr = strdup("error connecting to IPC$ pipe");
+ return NULL;
+ }
+
+ if (!cli_nt_session_open(cli, pipe_idx)) {
+ cli_shutdown(cli);
+ asprintf(errstr, "error opening pipe index %d", pipe_idx);
+ return NULL;
+ }
+
+ *errstr = NULL;
+
+ return cli;
+}
+
+/* Return true if a dictionary contains a "level" key with an integer
+ value. Set the value if so. */
+
+BOOL get_level_value(PyObject *dict, uint32 *level)
+{
+ PyObject *obj;
+
+ if (!(obj = PyDict_GetItemString(dict, "level")) ||
+ !PyInt_Check(obj))
+ return False;
+
+ if (level)
+ *level = PyInt_AsLong(obj);
+
+ return True;
+}
diff --git a/source4/python/py_common.h b/source4/python/py_common.h
new file mode 100644
index 0000000000..2bbd148ff4
--- /dev/null
+++ b/source4/python/py_common.h
@@ -0,0 +1,67 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002-2003
+
+ 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.
+*/
+
+#ifndef _PY_COMMON_H
+#define _PY_COMMON_H
+
+#include "includes.h"
+
+/* This symbol is used in both includes.h and Python.h which causes an
+ annoying compiler warning. */
+
+#ifdef HAVE_FSTAT
+#undef HAVE_FSTAT
+#endif
+
+#include "Python.h"
+
+/* Return a cli_state struct opened on the specified pipe. If credentials
+ are passed use them. */
+
+typedef struct cli_state *(cli_pipe_fn)(
+ struct cli_state *cli, char *system_name,
+ struct ntuser_creds *creds);
+
+/* The following definitions come from python/py_common.c */
+
+PyObject *py_werror_tuple(WERROR werror);
+PyObject *py_ntstatus_tuple(NTSTATUS ntstatus);
+void py_samba_init(void);
+PyObject *get_debuglevel(PyObject *self, PyObject *args);
+PyObject *set_debuglevel(PyObject *self, PyObject *args);
+PyObject *py_setup_logging(PyObject *self, PyObject *args, PyObject *kw);
+BOOL py_parse_creds(PyObject *creds, char **username, char **domain,
+ char **password, char **errstr);
+struct cli_state *open_pipe_creds(char *server, PyObject *creds,
+ int pipe_idx, char **errstr);
+BOOL get_level_value(PyObject *dict, uint32 *level);
+
+/* The following definitions come from python/py_ntsec.c */
+
+BOOL py_from_SID(PyObject **obj, DOM_SID *sid);
+BOOL py_to_SID(DOM_SID *sid, PyObject *obj);
+BOOL py_from_ACE(PyObject **dict, SEC_ACE *ace);
+BOOL py_to_ACE(SEC_ACE *ace, PyObject *dict);
+BOOL py_from_ACL(PyObject **dict, SEC_ACL *acl);
+BOOL py_to_ACL(SEC_ACL *acl, PyObject *dict, TALLOC_CTX *mem_ctx);
+BOOL py_from_SECDESC(PyObject **dict, SEC_DESC *sd);
+BOOL py_to_SECDESC(SEC_DESC **sd, PyObject *dict, TALLOC_CTX *mem_ctx);
+
+#endif /* _PY_COMMON_H */
diff --git a/source4/python/py_conv.c b/source4/python/py_conv.c
new file mode 100644
index 0000000000..d0a2d78aab
--- /dev/null
+++ b/source4/python/py_conv.c
@@ -0,0 +1,223 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "py_conv.h"
+
+/* Helper for rpcstr_pull() function */
+
+static void fstr_pull(fstring str, UNISTR *uni)
+{
+ rpcstr_pull(str, uni->buffer, sizeof(fstring), -1, STR_TERMINATE);
+}
+
+static void fstr_pull2(fstring str, UNISTR2 *uni)
+{
+ rpcstr_pull(str, uni->buffer, sizeof(fstring), -1, STR_TERMINATE);
+}
+
+/* Convert a structure to a Python dict */
+
+PyObject *from_struct(void *s, struct pyconv *conv)
+{
+ PyObject *obj, *item;
+ int i;
+
+ obj = PyDict_New();
+
+ for (i = 0; conv[i].name; i++) {
+ switch (conv[i].type) {
+ case PY_UNISTR: {
+ UNISTR *u = (UNISTR *)((char *)s + conv[i].offset);
+ fstring str = "";
+
+ if (u->buffer)
+ fstr_pull(str, u);
+
+ item = PyString_FromString(str);
+ PyDict_SetItemString(obj, conv[i].name, item);
+
+ break;
+ }
+ case PY_UNISTR2: {
+ UNISTR2 *u = (UNISTR2 *)((char *)s + conv[i].offset);
+ fstring str = "";
+
+ if (u->buffer)
+ fstr_pull2(str, u);
+
+ item = PyString_FromString(str);
+ PyDict_SetItemString(obj, conv[i].name, item);
+
+ break;
+ }
+ case PY_UINT32: {
+ uint32 *u = (uint32 *)((char *)s + conv[i].offset);
+
+ item = PyInt_FromLong(*u);
+ PyDict_SetItemString(obj, conv[i].name, item);
+
+ break;
+ }
+ case PY_UINT16: {
+ uint16 *u = (uint16 *)((char *)s + conv[i].offset);
+
+ item = PyInt_FromLong(*u);
+ PyDict_SetItemString(obj, conv[i].name, item);
+
+ break;
+ }
+ case PY_STRING: {
+ char *str = (char *)s + conv[i].offset;
+
+ item = PyString_FromString(str);
+ PyDict_SetItemString(obj, conv[i].name, item);
+
+ break;
+ }
+ case PY_UID: {
+ uid_t *uid = (uid_t *)((char *)s + conv[i].offset);
+
+ item = PyInt_FromLong(*uid);
+ PyDict_SetItemString(obj, conv[i].name, item);
+
+ break;
+ }
+ case PY_GID: {
+ gid_t *gid = (gid_t *)((char *)s + conv[i].offset);
+
+ item = PyInt_FromLong(*gid);
+ PyDict_SetItemString(obj, conv[i].name, item);
+
+ break;
+ }
+ default:
+
+ break;
+ }
+ }
+
+ return obj;
+}
+
+/* Convert a Python dict to a structure */
+
+BOOL to_struct(void *s, PyObject *dict, struct pyconv *conv)
+{
+ PyObject *visited, *key, *value;
+ BOOL result = False;
+ int i;
+
+ visited = PyDict_New();
+
+ for (i = 0; conv[i].name; i++) {
+ PyObject *obj;
+
+ obj = PyDict_GetItemString(dict, conv[i].name);
+
+ if (!obj)
+ goto done;
+
+ switch (conv[i].type) {
+ case PY_UNISTR: {
+ UNISTR *u = (UNISTR *)((char *)s + conv[i].offset);
+ char *str = "";
+
+ if (!PyString_Check(obj))
+ goto done;
+
+ str = PyString_AsString(obj);
+ init_unistr(u, str);
+
+ break;
+ }
+ case PY_UINT32: {
+ uint32 *u = (uint32 *)((char *)s + conv[i].offset);
+
+ if (!PyInt_Check(obj))
+ goto done;
+
+ *u = PyInt_AsLong(obj);
+
+ break;
+ }
+ case PY_UINT16: {
+ uint16 *u = (uint16 *)((char *)s + conv[i].offset);
+
+ if (!PyInt_Check(obj))
+ goto done;
+
+ *u = PyInt_AsLong(obj);
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* Mark as visited */
+
+ PyDict_SetItemString(visited, conv[i].name,
+ PyInt_FromLong(1));
+ }
+
+ /* Iterate over each item in the input dictionary and see if it was
+ visited. If it wasn't then the user has added some extra crap
+ to the dictionary. */
+
+ i = 0;
+
+ while (PyDict_Next(dict, &i, &key, &value)) {
+ if (!PyDict_GetItem(visited, key))
+ goto done;
+ }
+
+ result = True;
+
+done:
+ /* We must decrement the reference count here or the visited
+ dictionary will not be freed. */
+
+ Py_DECREF(visited);
+
+ return result;
+}
+
+/* Convert a NULL terminated list of NULL terminated unicode strings
+ to a list of (char *) strings */
+
+PyObject *from_unistr_list(uint16 *dependentfiles)
+{
+ PyObject *list;
+ int offset = 0;
+
+ list = PyList_New(0);
+
+ while (*(dependentfiles + offset) != 0) {
+ fstring name;
+ int len;
+
+ len = rpcstr_pull(name, dependentfiles + offset,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ offset += len / 2;
+ PyList_Append(list, PyString_FromString(name));
+ }
+
+ return list;
+}
diff --git a/source4/python/py_conv.h b/source4/python/py_conv.h
new file mode 100644
index 0000000000..798661c3a0
--- /dev/null
+++ b/source4/python/py_conv.h
@@ -0,0 +1,44 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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.
+*/
+
+#ifndef _PY_CONV_H
+#define _PY_CONV_H
+
+#include "python/py_common.h"
+
+enum pyconv_types { PY_UNISTR, PY_UNISTR2, PY_UINT32, PY_UINT16, PY_STRING,
+ PY_UID, PY_GID };
+
+struct pyconv {
+ char *name; /* Name of member */
+ enum pyconv_types type; /* Type */
+ size_t offset; /* Offset into structure */
+};
+
+PyObject *from_struct(void *s, struct pyconv *conv);
+BOOL to_struct(void *s, PyObject *dict, struct pyconv *conv);
+PyObject *from_unistr_list(uint16 *dependentfiles);
+
+/* Another version of offsetof (-: */
+
+#undef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#endif /* _PY_CONV_H */
diff --git a/source4/python/py_lsa.c b/source4/python/py_lsa.c
new file mode 100644
index 0000000000..22db29665a
--- /dev/null
+++ b/source4/python/py_lsa.c
@@ -0,0 +1,468 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_lsa.h"
+
+PyObject *new_lsa_policy_hnd_object(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol)
+{
+ lsa_policy_hnd_object *o;
+
+ o = PyObject_New(lsa_policy_hnd_object, &lsa_policy_hnd_type);
+
+ o->cli = cli;
+ o->mem_ctx = mem_ctx;
+ memcpy(&o->pol, pol, sizeof(POLICY_HND));
+
+ return (PyObject*)o;
+}
+
+/*
+ * Exceptions raised by this module
+ */
+
+PyObject *lsa_error; /* This indicates a non-RPC related error
+ such as name lookup failure */
+
+PyObject *lsa_ntstatus; /* This exception is raised when a RPC call
+ returns a status code other than
+ NT_STATUS_OK */
+
+/*
+ * Open/close lsa handles
+ */
+
+static PyObject *lsa_open_policy(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ static char *kwlist[] = { "servername", "creds", "access", NULL };
+ char *server, *errstr;
+ PyObject *creds = NULL, *result = NULL;
+ uint32 desired_access = MAXIMUM_ALLOWED_ACCESS;
+ struct cli_state *cli = NULL;
+ NTSTATUS ntstatus;
+ TALLOC_CTX *mem_ctx = NULL;
+ POLICY_HND hnd;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s|Oi", kwlist, &server, &creds, &desired_access))
+ return NULL;
+
+ if (creds && creds != Py_None && !PyDict_Check(creds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "credentials must be dictionary or None");
+ return NULL;
+ }
+
+ if (server[0] != '\\' || server[1] != '\\') {
+ PyErr_SetString(PyExc_ValueError, "UNC name required");
+ return NULL;
+ }
+
+ server += 2;
+
+ if (!(cli = open_pipe_creds(server, creds, PI_LSARPC, &errstr))) {
+ PyErr_SetString(lsa_error, errstr);
+ free(errstr);
+ return NULL;
+ }
+
+ if (!(mem_ctx = talloc_init("lsa_open_policy"))) {
+ PyErr_SetString(lsa_error, "unable to init talloc context\n");
+ goto done;
+ }
+
+ ntstatus = cli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, &hnd);
+
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ PyErr_SetObject(lsa_ntstatus, py_ntstatus_tuple(ntstatus));
+ goto done;
+ }
+
+ result = new_lsa_policy_hnd_object(cli, mem_ctx, &hnd);
+
+done:
+ if (!result) {
+ if (cli)
+ cli_shutdown(cli);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ }
+
+ return result;
+}
+
+static PyObject *lsa_close(PyObject *self, PyObject *args, PyObject *kw)
+{
+ PyObject *po;
+ lsa_policy_hnd_object *hnd;
+ NTSTATUS result;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTuple(args, "O!", &lsa_policy_hnd_type, &po))
+ return NULL;
+
+ hnd = (lsa_policy_hnd_object *)po;
+
+ /* Call rpc function */
+
+ result = cli_lsa_close(hnd->cli, hnd->mem_ctx, &hnd->pol);
+
+ /* Cleanup samba stuff */
+
+ cli_shutdown(hnd->cli);
+ talloc_destroy(hnd->mem_ctx);
+
+ /* Return value */
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *lsa_lookup_names(PyObject *self, PyObject *args)
+{
+ PyObject *py_names, *result;
+ NTSTATUS ntstatus;
+ lsa_policy_hnd_object *hnd = (lsa_policy_hnd_object *)self;
+ int num_names, i;
+ const char **names;
+ DOM_SID *sids;
+ uint32 *name_types;
+
+ if (!PyArg_ParseTuple(args, "O", &py_names))
+ return NULL;
+
+ if (!PyList_Check(py_names) && !PyString_Check(py_names)) {
+ PyErr_SetString(PyExc_TypeError, "must be list or string");
+ return NULL;
+ }
+
+ if (PyList_Check(py_names)) {
+
+ /* Convert list to char ** array */
+
+ num_names = PyList_Size(py_names);
+ names = (const char **)talloc(
+ hnd->mem_ctx, num_names * sizeof(char *));
+
+ for (i = 0; i < num_names; i++) {
+ PyObject *obj = PyList_GetItem(py_names, i);
+
+ names[i] = talloc_strdup(hnd->mem_ctx, PyString_AsString(obj));
+ }
+
+ } else {
+
+ /* Just a single element */
+
+ num_names = 1;
+ names = (const char **)talloc(hnd->mem_ctx, sizeof(char *));
+
+ names[0] = PyString_AsString(py_names);
+ }
+
+ ntstatus = cli_lsa_lookup_names(hnd->cli, hnd->mem_ctx, &hnd->pol,
+ num_names, names, &sids, &name_types);
+
+ if (!NT_STATUS_IS_OK(ntstatus) && NT_STATUS_V(ntstatus) != 0x107) {
+ PyErr_SetObject(lsa_ntstatus, py_ntstatus_tuple(ntstatus));
+ return NULL;
+ }
+
+ result = PyList_New(num_names);
+
+ for (i = 0; i < num_names; i++) {
+ PyObject *sid_obj, *obj;
+
+ py_from_SID(&sid_obj, &sids[i]);
+
+ obj = Py_BuildValue("(Oi)", sid_obj, name_types[i]);
+
+ PyList_SetItem(result, i, obj);
+ }
+
+ return result;
+}
+
+static PyObject *lsa_lookup_sids(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ PyObject *py_sids, *result;
+ NTSTATUS ntstatus;
+ int num_sids, i;
+ char **domains, **names;
+ uint32 *types;
+ lsa_policy_hnd_object *hnd = (lsa_policy_hnd_object *)self;
+ DOM_SID *sids;
+
+ if (!PyArg_ParseTuple(args, "O", &py_sids))
+ return NULL;
+
+ if (!PyList_Check(py_sids) && !PyString_Check(py_sids)) {
+ PyErr_SetString(PyExc_TypeError, "must be list or string");
+ return NULL;
+ }
+
+ if (PyList_Check(py_sids)) {
+
+ /* Convert dictionary to char ** array */
+
+ num_sids = PyList_Size(py_sids);
+ sids = (DOM_SID *)talloc(hnd->mem_ctx, num_sids * sizeof(DOM_SID));
+
+ memset(sids, 0, num_sids * sizeof(DOM_SID));
+
+ for (i = 0; i < num_sids; i++) {
+ PyObject *obj = PyList_GetItem(py_sids, i);
+
+ if (!string_to_sid(&sids[i], PyString_AsString(obj))) {
+ PyErr_SetString(PyExc_ValueError, "string_to_sid failed");
+ return NULL;
+ }
+ }
+
+ } else {
+
+ /* Just a single element */
+
+ num_sids = 1;
+ sids = (DOM_SID *)talloc(hnd->mem_ctx, sizeof(DOM_SID));
+
+ if (!string_to_sid(&sids[0], PyString_AsString(py_sids))) {
+ PyErr_SetString(PyExc_ValueError, "string_to_sid failed");
+ return NULL;
+ }
+ }
+
+ ntstatus = cli_lsa_lookup_sids(hnd->cli, hnd->mem_ctx, &hnd->pol,
+ num_sids, sids, &domains, &names,
+ &types);
+
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ PyErr_SetObject(lsa_ntstatus, py_ntstatus_tuple(ntstatus));
+ return NULL;
+ }
+
+ result = PyList_New(num_sids);
+
+ for (i = 0; i < num_sids; i++) {
+ PyObject *obj;
+
+ obj = Py_BuildValue("{sssssi}", "username", names[i],
+ "domain", domains[i], "name_type",
+ types[i]);
+
+ PyList_SetItem(result, i, obj);
+ }
+
+ return result;
+}
+
+static PyObject *lsa_enum_trust_dom(PyObject *self, PyObject *args)
+{
+ lsa_policy_hnd_object *hnd = (lsa_policy_hnd_object *)self;
+ NTSTATUS ntstatus;
+ uint32 enum_ctx = 0, num_domains, i;
+ char **domain_names;
+ DOM_SID *domain_sids;
+ PyObject *result;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ ntstatus = cli_lsa_enum_trust_dom(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, &enum_ctx,
+ &num_domains, &domain_names, &domain_sids);
+
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ PyErr_SetObject(lsa_ntstatus, py_ntstatus_tuple(ntstatus));
+ return NULL;
+ }
+
+ result = PyList_New(num_domains);
+
+ for (i = 0; i < num_domains; i++) {
+ fstring sid_str;
+
+ sid_to_string(sid_str, &domain_sids[i]);
+ PyList_SetItem(
+ result, i,
+ Py_BuildValue("(ss)", domain_names[i], sid_str));
+ }
+
+ return result;
+}
+
+/*
+ * Method dispatch tables
+ */
+
+static PyMethodDef lsa_hnd_methods[] = {
+
+ /* SIDs<->names */
+
+ { "lookup_sids", (PyCFunction)lsa_lookup_sids,
+ METH_VARARGS | METH_KEYWORDS,
+ "Convert sids to names." },
+
+ { "lookup_names", (PyCFunction)lsa_lookup_names,
+ METH_VARARGS | METH_KEYWORDS,
+ "Convert names to sids." },
+
+ /* Trusted domains */
+
+ { "enum_trusted_domains", (PyCFunction)lsa_enum_trust_dom,
+ METH_VARARGS,
+ "Enumerate trusted domains." },
+
+ { NULL }
+};
+
+static void py_lsa_policy_hnd_dealloc(PyObject* self)
+{
+ PyObject_Del(self);
+}
+
+static PyObject *py_lsa_policy_hnd_getattr(PyObject *self, char *attrname)
+{
+ return Py_FindMethod(lsa_hnd_methods, self, attrname);
+}
+
+PyTypeObject lsa_policy_hnd_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "LSA Policy Handle",
+ sizeof(lsa_policy_hnd_object),
+ 0,
+ py_lsa_policy_hnd_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ py_lsa_policy_hnd_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+};
+
+static PyMethodDef lsa_methods[] = {
+
+ /* Open/close lsa handles */
+
+ { "open_policy", (PyCFunction)lsa_open_policy,
+ METH_VARARGS | METH_KEYWORDS,
+ "Open a policy handle" },
+
+ { "close", (PyCFunction)lsa_close,
+ METH_VARARGS,
+ "Close a policy handle" },
+
+ /* Other stuff - this should really go into a samba config module
+ but for the moment let's leave it here. */
+
+ { "setup_logging", (PyCFunction)py_setup_logging,
+ METH_VARARGS | METH_KEYWORDS,
+ "Set up debug logging.
+
+Initialises Samba's debug logging system. One argument is expected which
+is a boolean specifying whether debugging is interactive and sent to stdout
+or logged to a file.
+
+Example:
+
+>>> spoolss.setup_logging(interactive = 1)" },
+
+ { "get_debuglevel", (PyCFunction)get_debuglevel,
+ METH_VARARGS,
+ "Set the current debug level.
+
+Example:
+
+>>> spoolss.get_debuglevel()
+0" },
+
+ { "set_debuglevel", (PyCFunction)set_debuglevel,
+ METH_VARARGS,
+ "Get the current debug level.
+
+Example:
+
+>>> spoolss.set_debuglevel(10)" },
+
+ { NULL }
+};
+
+static struct const_vals {
+ char *name;
+ uint32 value;
+} module_const_vals[] = {
+ { NULL }
+};
+
+static void const_init(PyObject *dict)
+{
+ struct const_vals *tmp;
+ PyObject *obj;
+
+ for (tmp = module_const_vals; tmp->name; tmp++) {
+ obj = PyInt_FromLong(tmp->value);
+ PyDict_SetItemString(dict, tmp->name, obj);
+ Py_DECREF(obj);
+ }
+}
+
+/*
+ * Module initialisation
+ */
+
+void initlsa(void)
+{
+ PyObject *module, *dict;
+
+ /* Initialise module */
+
+ module = Py_InitModule("lsa", lsa_methods);
+ dict = PyModule_GetDict(module);
+
+ lsa_error = PyErr_NewException("lsa.error", NULL, NULL);
+ PyDict_SetItemString(dict, "error", lsa_error);
+
+ lsa_ntstatus = PyErr_NewException("lsa.ntstatus", NULL, NULL);
+ PyDict_SetItemString(dict, "ntstatus", lsa_ntstatus);
+
+ /* Initialise policy handle object */
+
+ lsa_policy_hnd_type.ob_type = &PyType_Type;
+
+ /* Initialise constants */
+
+ const_init(dict);
+
+ /* Do samba initialisation */
+
+ py_samba_init();
+
+ setup_logging("lsa", True);
+ DEBUGLEVEL = 10;
+}
diff --git a/source4/python/py_lsa.h b/source4/python/py_lsa.h
new file mode 100644
index 0000000000..99f3de50b1
--- /dev/null
+++ b/source4/python/py_lsa.h
@@ -0,0 +1,41 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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.
+*/
+
+#ifndef _PY_LSA_H
+#define _PY_LSA_H
+
+#include "python/py_common.h"
+
+/* LSA policy handle object */
+
+typedef struct {
+ PyObject_HEAD
+ struct cli_state *cli;
+ TALLOC_CTX *mem_ctx;
+ POLICY_HND pol;
+} lsa_policy_hnd_object;
+
+/* Exceptions raised by this module */
+
+extern PyTypeObject lsa_policy_hnd_type;
+
+extern PyObject *lsa_error;
+
+#endif /* _PY_LSA_H */
diff --git a/source4/python/py_ntsec.c b/source4/python/py_ntsec.c
new file mode 100644
index 0000000000..47524d8e19
--- /dev/null
+++ b/source4/python/py_ntsec.c
@@ -0,0 +1,281 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_common.h"
+
+/* Convert a SID to a Python dict */
+
+BOOL py_from_SID(PyObject **obj, DOM_SID *sid)
+{
+ fstring sidstr;
+
+ if (!sid) {
+ Py_INCREF(Py_None);
+ *obj = Py_None;
+ return True;
+ }
+
+ if (!sid_to_string(sidstr, sid))
+ return False;
+
+ *obj = PyString_FromString(sidstr);
+
+ return True;
+}
+
+BOOL py_to_SID(DOM_SID *sid, PyObject *obj)
+{
+ if (!PyString_Check(obj))
+ return False;
+
+ return string_to_sid(sid, PyString_AsString(obj));
+}
+
+BOOL py_from_ACE(PyObject **dict, SEC_ACE *ace)
+{
+ PyObject *obj;
+
+ if (!ace) {
+ Py_INCREF(Py_None);
+ *dict = Py_None;
+ return True;
+ }
+
+ *dict = PyDict_New();
+
+ PyDict_SetItemString(*dict, "type", PyInt_FromLong(ace->type));
+ PyDict_SetItemString(*dict, "flags", PyInt_FromLong(ace->flags));
+ PyDict_SetItemString(*dict, "mask", PyInt_FromLong(ace->info.mask));
+
+ if (py_from_SID(&obj, &ace->trustee))
+ PyDict_SetItemString(*dict, "trustee", obj);
+
+ return True;
+}
+
+BOOL py_to_ACE(SEC_ACE *ace, PyObject *dict)
+{
+ PyObject *obj;
+ uint8 ace_type, ace_flags;
+ DOM_SID trustee;
+ SEC_ACCESS sec_access;
+
+ if (!PyDict_Check(dict))
+ return False;
+
+ if (!(obj = PyDict_GetItemString(dict, "type")) ||
+ !PyInt_Check(obj))
+ return False;
+
+ ace_type = PyInt_AsLong(obj);
+
+ if (!(obj = PyDict_GetItemString(dict, "flags")) ||
+ !PyInt_Check(obj))
+ return False;
+
+ ace_flags = PyInt_AsLong(obj);
+
+ if (!(obj = PyDict_GetItemString(dict, "trustee")) ||
+ !PyString_Check(obj))
+ return False;
+
+ if (!py_to_SID(&trustee, obj))
+ return False;
+
+ if (!(obj = PyDict_GetItemString(dict, "mask")) ||
+ !PyInt_Check(obj))
+ return False;
+
+ sec_access.mask = PyInt_AsLong(obj);
+
+ init_sec_ace(ace, &trustee, ace_type, sec_access, ace_flags);
+
+ /* Fill in size field */
+
+ ace->size = SEC_ACE_HEADER_SIZE + sid_size(&trustee);
+
+ return True;
+}
+
+BOOL py_from_ACL(PyObject **dict, SEC_ACL *acl)
+{
+ PyObject *ace_list;
+ int i;
+
+ if (!acl) {
+ Py_INCREF(Py_None);
+ *dict = Py_None;
+ return True;
+ }
+
+ *dict = PyDict_New();
+
+ PyDict_SetItemString(*dict, "revision", PyInt_FromLong(acl->revision));
+
+ ace_list = PyList_New(acl->num_aces);
+
+ for (i = 0; i < acl->num_aces; i++) {
+ PyObject *obj;
+
+ if (py_from_ACE(&obj, &acl->ace[i]))
+ PyList_SetItem(ace_list, i, obj);
+ }
+
+ PyDict_SetItemString(*dict, "ace_list", ace_list);
+
+ return True;
+}
+
+BOOL py_to_ACL(SEC_ACL *acl, PyObject *dict, TALLOC_CTX *mem_ctx)
+{
+ PyObject *obj;
+ uint32 i;
+
+ if (!(obj = PyDict_GetItemString(dict, "revision")) ||
+ !PyInt_Check(obj))
+ return False;
+
+ acl->revision = PyInt_AsLong(obj);
+
+ if (!(obj = PyDict_GetItemString(dict, "ace_list")) ||
+ !PyList_Check(obj))
+ return False;
+
+ acl->num_aces = PyList_Size(obj);
+
+ acl->ace = talloc(mem_ctx, acl->num_aces * sizeof(SEC_ACE));
+ acl->size = SEC_ACL_HEADER_SIZE;
+
+ for (i = 0; i < acl->num_aces; i++) {
+ PyObject *py_ace = PyList_GetItem(obj, i);
+
+ if (!py_to_ACE(&acl->ace[i], py_ace))
+ return False;
+
+ acl->size += acl->ace[i].size;
+ }
+
+ return True;
+}
+
+BOOL py_from_SECDESC(PyObject **dict, SEC_DESC *sd)
+{
+ PyObject *obj;
+
+ *dict = PyDict_New();
+
+ PyDict_SetItemString(*dict, "revision", PyInt_FromLong(sd->revision));
+
+ if (py_from_SID(&obj, sd->owner_sid))
+ PyDict_SetItemString(*dict, "owner_sid", obj);
+
+ if (py_from_SID(&obj, sd->grp_sid))
+ PyDict_SetItemString(*dict, "group_sid", obj);
+
+ if (py_from_ACL(&obj, sd->dacl))
+ PyDict_SetItemString(*dict, "dacl", obj);
+
+ if (py_from_ACL(&obj, sd->sacl))
+ PyDict_SetItemString(*dict, "sacl", obj);
+
+ return True;
+}
+
+BOOL py_to_SECDESC(SEC_DESC **sd, PyObject *dict, TALLOC_CTX *mem_ctx)
+{
+ PyObject *obj;
+ uint16 revision;
+ DOM_SID owner_sid, group_sid;
+ SEC_ACL sacl, dacl;
+ BOOL got_dacl = False, got_sacl = False;
+ BOOL got_owner_sid = False, got_group_sid = False;
+
+ ZERO_STRUCT(dacl); ZERO_STRUCT(sacl);
+ ZERO_STRUCT(owner_sid); ZERO_STRUCT(group_sid);
+
+ if (!(obj = PyDict_GetItemString(dict, "revision")))
+ return False;
+
+ revision = PyInt_AsLong(obj);
+
+ if ((obj = PyDict_GetItemString(dict, "owner_sid"))) {
+
+ if (obj != Py_None) {
+
+ if (!py_to_SID(&owner_sid, obj))
+ return False;
+
+ got_owner_sid = True;
+ }
+ }
+
+ if ((obj = PyDict_GetItemString(dict, "group_sid"))) {
+
+ if (obj != Py_None) {
+
+ if (!py_to_SID(&group_sid, obj))
+ return False;
+
+ got_group_sid = True;
+ }
+ }
+
+ if ((obj = PyDict_GetItemString(dict, "dacl"))) {
+
+ if (obj != Py_None) {
+
+ if (!py_to_ACL(&dacl, obj, mem_ctx))
+ return False;
+
+ got_dacl = True;
+ }
+ }
+
+ if ((obj = PyDict_GetItemString(dict, "sacl"))) {
+
+ if (obj != Py_None) {
+
+ if (!py_to_ACL(&sacl, obj, mem_ctx))
+ return False;
+
+ got_sacl = True;
+ }
+ }
+
+#if 0 /* For new secdesc code */
+ *sd = make_sec_desc(mem_ctx, revision,
+ got_owner_sid ? &owner_sid : NULL,
+ got_group_sid ? &group_sid : NULL,
+ got_sacl ? &sacl : NULL,
+ got_dacl ? &dacl : NULL);
+#else
+ {
+ size_t sd_size;
+
+ *sd = make_sec_desc(mem_ctx, revision,
+ got_owner_sid ? &owner_sid : NULL,
+ got_group_sid ? &group_sid : NULL,
+ got_sacl ? &sacl : NULL,
+ got_dacl ? &dacl : NULL, &sd_size);
+ }
+#endif
+
+ return True;
+}
diff --git a/source4/python/py_samba.c b/source4/python/py_samba.c
new file mode 100644
index 0000000000..c0ade12f65
--- /dev/null
+++ b/source4/python/py_samba.c
@@ -0,0 +1,56 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "Python.h"
+#include "python/py_common.h"
+
+/*
+ * Module initialisation
+ */
+
+static PyObject *lsa_open_policy(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ return NULL;
+}
+
+static PyMethodDef samba_methods[] = {
+ { NULL }
+};
+
+static PyMethodDef cheepy_methods[] = {
+ { "open_policy", (PyCFunction)lsa_open_policy, METH_VARARGS|METH_KEYWORDS,
+ "Foo"},
+ { NULL }
+};
+
+void initsamba(void)
+{
+ PyObject *module, *new_module, *dict;
+
+ /* Initialise module */
+
+ module = Py_InitModule("samba", samba_methods);
+ dict = PyModule_GetDict(module);
+
+ /* Do samba initialisation */
+
+ py_samba_init();
+}
diff --git a/source4/python/py_samr.c b/source4/python/py_samr.c
new file mode 100644
index 0000000000..182671d047
--- /dev/null
+++ b/source4/python/py_samr.c
@@ -0,0 +1,497 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_samr.h"
+
+/*
+ * Exceptions raised by this module
+ */
+
+PyObject *samr_error; /* This indicates a non-RPC related error
+ such as name lookup failure */
+
+PyObject *samr_ntstatus; /* This exception is raised when a RPC call
+ returns a status code other than
+ NT_STATUS_OK */
+
+/* SAMR connect handle object */
+
+static void py_samr_connect_hnd_dealloc(PyObject* self)
+{
+ PyObject_Del(self);
+}
+
+PyObject *new_samr_domain_hnd_object(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol)
+{
+ samr_domain_hnd_object *o;
+
+ o = PyObject_New(samr_domain_hnd_object, &samr_domain_hnd_type);
+
+ o->cli = cli;
+ o->mem_ctx = mem_ctx;
+ memcpy(&o->domain_pol, pol, sizeof(POLICY_HND));
+
+ return (PyObject*)o;
+}
+
+static PyObject *samr_open_domain(PyObject *self, PyObject *args, PyObject *kw)
+{
+ samr_connect_hnd_object *connect_hnd = (samr_connect_hnd_object *)self;
+ static char *kwlist[] = { "sid", "access", NULL };
+ uint32 desired_access = MAXIMUM_ALLOWED_ACCESS;
+ char *sid_str;
+ DOM_SID sid;
+ TALLOC_CTX *mem_ctx = NULL;
+ POLICY_HND domain_pol;
+ NTSTATUS ntstatus;
+ PyObject *result = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s|i", kwlist, &sid_str, &desired_access))
+ return NULL;
+
+ if (!string_to_sid(&sid, sid_str)) {
+ PyErr_SetString(PyExc_TypeError, "string is not a sid");
+ return NULL;
+ }
+
+ if (!(mem_ctx = talloc_init("samr_open_domain"))) {
+ PyErr_SetString(samr_error, "unable to init talloc context");
+ return NULL;
+ }
+
+ ntstatus = cli_samr_open_domain(
+ connect_hnd->cli, mem_ctx, &connect_hnd->connect_pol,
+ desired_access, &sid, &domain_pol);
+
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ PyErr_SetObject(samr_ntstatus, py_ntstatus_tuple(ntstatus));
+ goto done;
+ }
+
+ result = new_samr_domain_hnd_object(
+ connect_hnd->cli, mem_ctx, &domain_pol);
+
+done:
+ if (!result) {
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ }
+
+ return result;
+}
+
+static PyMethodDef samr_connect_methods[] = {
+ { "open_domain", (PyCFunction)samr_open_domain,
+ METH_VARARGS | METH_KEYWORDS,
+ "Open a handle on a domain" },
+
+ { NULL }
+};
+
+static PyObject *py_samr_connect_hnd_getattr(PyObject *self, char *attrname)
+{
+ return Py_FindMethod(samr_connect_methods, self, attrname);
+}
+
+PyTypeObject samr_connect_hnd_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "SAMR Connect Handle",
+ sizeof(samr_connect_hnd_object),
+ 0,
+ py_samr_connect_hnd_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ py_samr_connect_hnd_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+};
+
+PyObject *new_samr_connect_hnd_object(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol)
+{
+ samr_connect_hnd_object *o;
+
+ o = PyObject_New(samr_connect_hnd_object, &samr_connect_hnd_type);
+
+ o->cli = cli;
+ o->mem_ctx = mem_ctx;
+ memcpy(&o->connect_pol, pol, sizeof(POLICY_HND));
+
+ return (PyObject*)o;
+}
+
+/* SAMR domain handle object */
+
+static void py_samr_domain_hnd_dealloc(PyObject* self)
+{
+ PyObject_Del(self);
+}
+
+static PyObject *samr_enum_dom_groups(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ samr_domain_hnd_object *domain_hnd = (samr_domain_hnd_object *)self;
+ static char *kwlist[] = { NULL };
+ TALLOC_CTX *mem_ctx;
+/* uint32 desired_access = MAXIMUM_ALLOWED_ACCESS; */
+ uint32 start_idx, size, num_dom_groups;
+ struct acct_info *dom_groups;
+ NTSTATUS result;
+ PyObject *py_result = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "", kwlist))
+ return NULL;
+
+ if (!(mem_ctx = talloc_init("samr_enum_dom_groups"))) {
+ PyErr_SetString(samr_error, "unable to init talloc context");
+ return NULL;
+ }
+
+ start_idx = 0;
+ size = 0xffff;
+
+ do {
+ result = cli_samr_enum_dom_groups(
+ domain_hnd->cli, mem_ctx, &domain_hnd->domain_pol,
+ &start_idx, size, &dom_groups, &num_dom_groups);
+
+ if (NT_STATUS_IS_OK(result) ||
+ NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES)) {
+ py_from_acct_info(&py_result, dom_groups,
+ num_dom_groups);
+ }
+
+ } while (NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES));
+
+ return py_result;
+}
+
+static PyMethodDef samr_domain_methods[] = {
+ { "enum_domain_groups", (PyCFunction)samr_enum_dom_groups,
+ METH_VARARGS | METH_KEYWORDS, "Enumerate domain groups" },
+ { NULL }
+};
+
+static PyObject *py_samr_domain_hnd_getattr(PyObject *self, char *attrname)
+{
+ return Py_FindMethod(samr_domain_methods, self, attrname);
+}
+
+PyTypeObject samr_domain_hnd_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "SAMR Domain Handle",
+ sizeof(samr_domain_hnd_object),
+ 0,
+ py_samr_domain_hnd_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ py_samr_domain_hnd_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+};
+
+/* SAMR user handle object */
+
+static void py_samr_user_hnd_dealloc(PyObject* self)
+{
+ PyObject_Del(self);
+}
+
+static PyMethodDef samr_user_methods[] = {
+ { NULL }
+};
+
+static PyObject *py_samr_user_hnd_getattr(PyObject *self, char *attrname)
+{
+ return Py_FindMethod(samr_user_methods, self, attrname);
+}
+
+PyTypeObject samr_user_hnd_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "SAMR User Handle",
+ sizeof(samr_user_hnd_object),
+ 0,
+ py_samr_user_hnd_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ py_samr_user_hnd_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+};
+
+PyObject *new_samr_user_hnd_object(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol)
+{
+ samr_user_hnd_object *o;
+
+ o = PyObject_New(samr_user_hnd_object, &samr_user_hnd_type);
+
+ o->cli = cli;
+ o->mem_ctx = mem_ctx;
+ memcpy(&o->user_pol, pol, sizeof(POLICY_HND));
+
+ return (PyObject*)o;
+}
+
+/* SAMR group handle object */
+
+static void py_samr_group_hnd_dealloc(PyObject* self)
+{
+ PyObject_Del(self);
+}
+
+static PyMethodDef samr_group_methods[] = {
+ { NULL }
+};
+
+static PyObject *py_samr_group_hnd_getattr(PyObject *self, char *attrname)
+{
+ return Py_FindMethod(samr_group_methods, self, attrname);
+}
+
+PyTypeObject samr_group_hnd_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "SAMR Group Handle",
+ sizeof(samr_group_hnd_object),
+ 0,
+ py_samr_group_hnd_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ py_samr_group_hnd_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+};
+
+PyObject *new_samr_group_hnd_object(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol)
+{
+ samr_group_hnd_object *o;
+
+ o = PyObject_New(samr_group_hnd_object, &samr_group_hnd_type);
+
+ o->cli = cli;
+ o->mem_ctx = mem_ctx;
+ memcpy(&o->group_pol, pol, sizeof(POLICY_HND));
+
+ return (PyObject*)o;
+}
+
+/* Alias handle object */
+
+static void py_samr_alias_hnd_dealloc(PyObject* self)
+{
+ PyObject_Del(self);
+}
+
+static PyMethodDef samr_alias_methods[] = {
+ { NULL }
+};
+
+static PyObject *py_samr_alias_hnd_getattr(PyObject *self, char *attrname)
+{
+ return Py_FindMethod(samr_alias_methods, self, attrname);
+}
+
+PyTypeObject samr_alias_hnd_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "SAMR Alias Handle",
+ sizeof(samr_alias_hnd_object),
+ 0,
+ py_samr_alias_hnd_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ py_samr_alias_hnd_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+};
+
+PyObject *new_samr_alias_hnd_object(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol)
+{
+ samr_alias_hnd_object *o;
+
+ o = PyObject_New(samr_alias_hnd_object, &samr_alias_hnd_type);
+
+ o->cli = cli;
+ o->mem_ctx = mem_ctx;
+ memcpy(&o->alias_pol, pol, sizeof(POLICY_HND));
+
+ return (PyObject*)o;
+}
+
+static PyObject *samr_connect(PyObject *self, PyObject *args, PyObject *kw)
+{
+ static char *kwlist[] = { "server", "creds", "access", NULL };
+ uint32 desired_access = MAXIMUM_ALLOWED_ACCESS;
+ char *server, *errstr;
+ struct cli_state *cli = NULL;
+ POLICY_HND hnd;
+ TALLOC_CTX *mem_ctx = NULL;
+ PyObject *result = NULL, *creds = NULL;
+ NTSTATUS ntstatus;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s|Oi", kwlist, &server, &creds,
+ &desired_access))
+ return NULL;
+
+ if (server[0] != '\\' || server[1] != '\\') {
+ PyErr_SetString(PyExc_ValueError, "UNC name required");
+ return NULL;
+ }
+
+ server += 2;
+
+ if (creds && creds != Py_None && !PyDict_Check(creds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "credentials must be dictionary or None");
+ return NULL;
+ }
+
+ if (!(cli = open_pipe_creds(server, creds, PI_SAMR, &errstr))) {
+ PyErr_SetString(samr_error, errstr);
+ free(errstr);
+ return NULL;
+ }
+
+ if (!(mem_ctx = talloc_init("samr_connect"))) {
+ PyErr_SetString(samr_ntstatus,
+ "unable to init talloc context\n");
+ goto done;
+ }
+
+ ntstatus = cli_samr_connect(cli, mem_ctx, desired_access, &hnd);
+
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ cli_shutdown(cli);
+ PyErr_SetObject(samr_ntstatus, py_ntstatus_tuple(ntstatus));
+ goto done;
+ }
+
+ result = new_samr_connect_hnd_object(cli, mem_ctx, &hnd);
+
+done:
+ if (!result) {
+ if (cli)
+ cli_shutdown(cli);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ }
+
+ return result;
+}
+
+/*
+ * Module initialisation
+ */
+
+static PyMethodDef samr_methods[] = {
+
+ /* Open/close samr connect handles */
+
+ { "connect", (PyCFunction)samr_connect,
+ METH_VARARGS | METH_KEYWORDS,
+ "Open a connect handle" },
+
+ { NULL }
+};
+
+static struct const_vals {
+ char *name;
+ uint32 value;
+} module_const_vals[] = {
+ { NULL }
+};
+
+static void const_init(PyObject *dict)
+{
+ struct const_vals *tmp;
+ PyObject *obj;
+
+ for (tmp = module_const_vals; tmp->name; tmp++) {
+ obj = PyInt_FromLong(tmp->value);
+ PyDict_SetItemString(dict, tmp->name, obj);
+ Py_DECREF(obj);
+ }
+}
+
+void initsamr(void)
+{
+ PyObject *module, *dict;
+
+ /* Initialise module */
+
+ module = Py_InitModule("samr", samr_methods);
+ dict = PyModule_GetDict(module);
+
+ samr_error = PyErr_NewException("samr.error", NULL, NULL);
+ PyDict_SetItemString(dict, "error", samr_error);
+
+ samr_ntstatus = PyErr_NewException("samr.ntstatus", NULL, NULL);
+ PyDict_SetItemString(dict, "ntstatus", samr_ntstatus);
+
+ /* Initialise policy handle object */
+
+ samr_connect_hnd_type.ob_type = &PyType_Type;
+ samr_domain_hnd_type.ob_type = &PyType_Type;
+ samr_user_hnd_type.ob_type = &PyType_Type;
+ samr_group_hnd_type.ob_type = &PyType_Type;
+ samr_alias_hnd_type.ob_type = &PyType_Type;
+
+ /* Initialise constants */
+
+ const_init(dict);
+
+ /* Do samba initialisation */
+
+ py_samba_init();
+
+ setup_logging("samr", True);
+ DEBUGLEVEL = 10;
+}
diff --git a/source4/python/py_samr.h b/source4/python/py_samr.h
new file mode 100644
index 0000000000..3292eb97ec
--- /dev/null
+++ b/source4/python/py_samr.h
@@ -0,0 +1,81 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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.
+*/
+
+#ifndef _PY_SAMR_H
+#define _PY_SAMR_H
+
+#include "python/py_common.h"
+
+/* SAMR connect policy handle object */
+
+typedef struct {
+ PyObject_HEAD
+ struct cli_state *cli;
+ TALLOC_CTX *mem_ctx;
+ POLICY_HND connect_pol;
+} samr_connect_hnd_object;
+
+/* SAMR domain policy handle object */
+
+typedef struct {
+ PyObject_HEAD
+ struct cli_state *cli;
+ TALLOC_CTX *mem_ctx;
+ POLICY_HND domain_pol;
+} samr_domain_hnd_object;
+
+/* SAMR user policy handle object */
+
+typedef struct {
+ PyObject_HEAD
+ struct cli_state *cli;
+ TALLOC_CTX *mem_ctx;
+ POLICY_HND user_pol;
+} samr_user_hnd_object;
+
+/* SAMR group policy handle object */
+
+typedef struct {
+ PyObject_HEAD
+ struct cli_state *cli;
+ TALLOC_CTX *mem_ctx;
+ POLICY_HND group_pol;
+} samr_group_hnd_object;
+
+/* SAMR alias policy handle object */
+
+typedef struct {
+ PyObject_HEAD
+ struct cli_state *cli;
+ TALLOC_CTX *mem_ctx;
+ POLICY_HND alias_pol;
+} samr_alias_hnd_object;
+
+extern PyTypeObject samr_connect_hnd_type, samr_domain_hnd_type,
+ samr_user_hnd_type, samr_group_hnd_type, samr_alias_hnd_type;
+
+/* Exceptions raised by this module */
+
+extern PyObject *samr_error;
+
+/* The following definitions are from py_samr_conv.c */
+
+BOOL py_from_acct_info(PyObject **array, struct acct_info *info, int num_accts);
+#endif /* _PY_SAMR_H */
diff --git a/source4/python/py_samr_conv.c b/source4/python/py_samr_conv.c
new file mode 100644
index 0000000000..fdf71641e0
--- /dev/null
+++ b/source4/python/py_samr_conv.c
@@ -0,0 +1,58 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_samr.h"
+#include "python/py_conv.h"
+
+/*
+ * Convert between acct_info and Python
+ */
+
+BOOL py_from_acct_info(PyObject **array, struct acct_info *info, int num_accts)
+{
+ int i;
+
+ *array = PyList_New(num_accts);
+
+ for (i = 0; i < num_accts; i++) {
+ PyObject *obj;
+
+ obj = PyDict_New();
+
+ PyDict_SetItemString(
+ obj, "name", PyString_FromString(info[i].acct_name));
+
+ PyDict_SetItemString(
+ obj, "description",
+ PyString_FromString(info[i].acct_desc));
+
+ PyDict_SetItemString(obj, "rid", PyInt_FromLong(info[i].rid));
+
+ PyList_SetItem(*array, i, obj);
+ }
+
+ return True;
+}
+
+BOOL py_to_acct_info(PRINTER_INFO_3 *info, PyObject *dict,
+ TALLOC_CTX *mem_ctx)
+{
+ return False;
+}
diff --git a/source4/python/py_smb.c b/source4/python/py_smb.c
new file mode 100644
index 0000000000..3f05b5d7c6
--- /dev/null
+++ b/source4/python/py_smb.c
@@ -0,0 +1,399 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_smb.h"
+
+/* Create a new cli_state python object */
+
+PyObject *new_cli_state_object(struct cli_state *cli)
+{
+ cli_state_object *o;
+
+ o = PyObject_New(cli_state_object, &cli_state_type);
+
+ o->cli = cli;
+
+ return (PyObject*)o;
+}
+
+static PyObject *py_smb_connect(PyObject *self, PyObject *args, PyObject *kw)
+{
+ static char *kwlist[] = { "server", NULL };
+ struct cli_state *cli;
+ char *server;
+ struct in_addr ip;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "s", kwlist, &server))
+ return NULL;
+
+ if (!(cli = cli_initialise(NULL)))
+ return NULL;
+
+ ZERO_STRUCT(ip);
+
+ if (!cli_connect(cli, server, &ip))
+ return NULL;
+
+ return new_cli_state_object(cli);
+}
+
+static PyObject *py_smb_session_request(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ cli_state_object *cli = (cli_state_object *)self;
+ static char *kwlist[] = { "called", "calling", NULL };
+ char *calling_name = NULL, *called_name;
+ struct nmb_name calling, called;
+ BOOL result;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "s|s", kwlist, &called_name,
+ &calling_name))
+ return NULL;
+
+ if (!calling_name)
+ calling_name = lp_netbios_name();
+
+ make_nmb_name(&calling, calling_name, 0x00);
+ make_nmb_name(&called, called_name, 0x20);
+
+ result = cli_session_request(cli->cli, &calling, &called);
+
+ return Py_BuildValue("i", result);
+}
+
+static PyObject *py_smb_negprot(PyObject *self, PyObject *args, PyObject *kw)
+{
+ cli_state_object *cli = (cli_state_object *)self;
+ static char *kwlist[] = { NULL };
+ BOOL result;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "", kwlist))
+ return NULL;
+
+ result = cli_negprot(cli->cli);
+
+ return Py_BuildValue("i", result);
+}
+
+static PyObject *py_smb_session_setup(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ cli_state_object *cli = (cli_state_object *)self;
+ static char *kwlist[] = { "creds", NULL };
+ PyObject *creds;
+ char *username, *domain, *password, *errstr;
+ BOOL result;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "|O", kwlist, &creds))
+ return NULL;
+
+ if (!py_parse_creds(creds, &username, &domain, &password, &errstr)) {
+ free(errstr);
+ return NULL;
+ }
+
+ result = cli_session_setup(
+ cli->cli, username, password, strlen(password) + 1,
+ password, strlen(password) + 1, domain);
+
+ if (cli_is_error(cli->cli)) {
+ PyErr_SetString(PyExc_RuntimeError, "session setup failed");
+ return NULL;
+ }
+
+ return Py_BuildValue("i", result);
+}
+
+static PyObject *py_smb_tconx(PyObject *self, PyObject *args, PyObject *kw)
+{
+ cli_state_object *cli = (cli_state_object *)self;
+ static char *kwlist[] = { "service", NULL };
+ char *service;
+ BOOL result;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "s", kwlist, &service))
+ return NULL;
+
+ result = cli_send_tconX(
+ cli->cli, service, strequal(service, "IPC$") ? "IPC" :
+ "?????", "", 1);
+
+ if (cli_is_error(cli->cli)) {
+ PyErr_SetString(PyExc_RuntimeError, "tconx failed");
+ return NULL;
+ }
+
+ return Py_BuildValue("i", result);
+}
+
+static PyObject *py_smb_nt_create_andx(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ cli_state_object *cli = (cli_state_object *)self;
+ static char *kwlist[] = { "filename", "desired_access",
+ "file_attributes", "share_access",
+ "create_disposition", NULL };
+ char *filename;
+ uint32 desired_access, file_attributes = 0,
+ share_access = FILE_SHARE_READ | FILE_SHARE_WRITE,
+ create_disposition = FILE_EXISTS_OPEN, create_options = 0;
+ int result;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "si|iii", kwlist, &filename, &desired_access,
+ &file_attributes, &share_access, &create_disposition,
+ &create_options))
+ return NULL;
+
+ result = cli_nt_create_full(
+ cli->cli, filename, desired_access, file_attributes,
+ share_access, create_disposition, create_options);
+
+ if (cli_is_error(cli->cli)) {
+ PyErr_SetString(PyExc_RuntimeError, "nt_create_andx failed");
+ return NULL;
+ }
+
+ /* Return FID */
+
+ return PyInt_FromLong(result);
+}
+
+static PyObject *py_smb_close(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ cli_state_object *cli = (cli_state_object *)self;
+ static char *kwlist[] = { "fnum", NULL };
+ BOOL result;
+ int fnum;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "i", kwlist, &fnum))
+ return NULL;
+
+ result = cli_close(cli->cli, fnum);
+
+ return PyInt_FromLong(result);
+}
+
+static PyObject *py_smb_unlink(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ cli_state_object *cli = (cli_state_object *)self;
+ static char *kwlist[] = { "filename", NULL };
+ char *filename;
+ BOOL result;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s", kwlist, &filename))
+ return NULL;
+
+ result = cli_unlink(cli->cli, filename);
+
+ return PyInt_FromLong(result);
+}
+
+static PyObject *py_smb_query_secdesc(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ cli_state_object *cli = (cli_state_object *)self;
+ static char *kwlist[] = { "fnum", NULL };
+ PyObject *result;
+ SEC_DESC *secdesc = NULL;
+ int fnum;
+ TALLOC_CTX *mem_ctx;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "i", kwlist, &fnum))
+ return NULL;
+
+ mem_ctx = talloc_init("py_smb_query_secdesc");
+
+ secdesc = cli_query_secdesc(cli->cli, fnum, mem_ctx);
+
+ if (cli_is_error(cli->cli)) {
+ PyErr_SetString(PyExc_RuntimeError, "query_secdesc failed");
+ return NULL;
+ }
+
+ if (!secdesc) {
+ Py_INCREF(Py_None);
+ result = Py_None;
+ goto done;
+ }
+
+ if (!py_from_SECDESC(&result, secdesc)) {
+ PyErr_SetString(
+ PyExc_TypeError,
+ "Invalid security descriptor returned");
+ result = NULL;
+ goto done;
+ }
+
+ done:
+ talloc_destroy(mem_ctx);
+
+ return result;
+
+}
+
+static PyObject *py_smb_set_secdesc(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ cli_state_object *cli = (cli_state_object *)self;
+ static char *kwlist[] = { "fnum", "security_descriptor", NULL };
+ PyObject *py_secdesc;
+ SEC_DESC *secdesc;
+ TALLOC_CTX *mem_ctx = talloc_init("py_smb_set_secdesc");
+ int fnum;
+ BOOL result;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "iO", kwlist, &fnum, &py_secdesc))
+ return NULL;
+
+ if (!py_to_SECDESC(&secdesc, py_secdesc, mem_ctx)) {
+ PyErr_SetString(PyExc_TypeError,
+ "Invalid security descriptor");
+ return NULL;
+ }
+
+ result = cli_set_secdesc(cli->cli, fnum, secdesc);
+
+ if (cli_is_error(cli->cli)) {
+ PyErr_SetString(PyExc_RuntimeError, "set_secdesc failed");
+ return NULL;
+ }
+
+ return PyInt_FromLong(result);
+}
+
+static PyMethodDef smb_hnd_methods[] = {
+
+ /* Session and connection handling */
+
+ { "session_request", (PyCFunction)py_smb_session_request,
+ METH_VARARGS | METH_KEYWORDS, "Request a session" },
+
+ { "negprot", (PyCFunction)py_smb_negprot,
+ METH_VARARGS | METH_KEYWORDS, "Protocol negotiation" },
+
+ { "session_setup", (PyCFunction)py_smb_session_setup,
+ METH_VARARGS | METH_KEYWORDS, "Session setup" },
+
+ { "tconx", (PyCFunction)py_smb_tconx,
+ METH_VARARGS | METH_KEYWORDS, "Tree connect" },
+
+ /* File operations */
+
+ { "nt_create_andx", (PyCFunction)py_smb_nt_create_andx,
+ METH_VARARGS | METH_KEYWORDS, "NT Create&X" },
+
+ { "close", (PyCFunction)py_smb_close,
+ METH_VARARGS | METH_KEYWORDS, "Close" },
+
+ { "unlink", (PyCFunction)py_smb_unlink,
+ METH_VARARGS | METH_KEYWORDS, "Unlink" },
+
+ /* Security descriptors */
+
+ { "query_secdesc", (PyCFunction)py_smb_query_secdesc,
+ METH_VARARGS | METH_KEYWORDS, "Query security descriptor" },
+
+ { "set_secdesc", (PyCFunction)py_smb_set_secdesc,
+ METH_VARARGS | METH_KEYWORDS, "Set security descriptor" },
+
+ { NULL }
+};
+
+/*
+ * Method dispatch tables
+ */
+
+static PyMethodDef smb_methods[] = {
+
+ { "connect", (PyCFunction)py_smb_connect, METH_VARARGS | METH_KEYWORDS,
+ "Connect to a host" },
+
+ { NULL }
+};
+
+static void py_cli_state_dealloc(PyObject* self)
+{
+ PyObject_Del(self);
+}
+
+static PyObject *py_cli_state_getattr(PyObject *self, char *attrname)
+{
+ return Py_FindMethod(smb_hnd_methods, self, attrname);
+}
+
+PyTypeObject cli_state_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "SMB client connection",
+ sizeof(cli_state_object),
+ 0,
+ py_cli_state_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ py_cli_state_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+};
+
+/*
+ * Module initialisation
+ */
+
+void initsmb(void)
+{
+ PyObject *module, *dict;
+
+ /* Initialise module */
+
+ module = Py_InitModule("smb", smb_methods);
+ dict = PyModule_GetDict(module);
+
+ /* Initialise policy handle object */
+
+ cli_state_type.ob_type = &PyType_Type;
+
+ /* Do samba initialisation */
+
+ py_samba_init();
+
+ setup_logging("smb", True);
+ DEBUGLEVEL = 10;
+}
diff --git a/source4/python/py_smb.h b/source4/python/py_smb.h
new file mode 100644
index 0000000000..31bcf4aab2
--- /dev/null
+++ b/source4/python/py_smb.h
@@ -0,0 +1,39 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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.
+*/
+
+#ifndef _PY_SMB_H
+#define _PY_SMB_H
+
+#include "python/py_common.h"
+
+/* cli_state handle object */
+
+typedef struct {
+ PyObject_HEAD
+ struct cli_state *cli;
+} cli_state_object;
+
+/* Exceptions raised by this module */
+
+extern PyTypeObject cli_state_type;
+
+extern PyObject *smb_ntstatus;
+
+#endif /* _PY_SMB_H */
diff --git a/source4/python/py_spoolss.c b/source4/python/py_spoolss.c
new file mode 100644
index 0000000000..7b0a102b31
--- /dev/null
+++ b/source4/python/py_spoolss.c
@@ -0,0 +1,484 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+
+/* Exceptions this module can raise */
+
+PyObject *spoolss_error, *spoolss_werror;
+
+/*
+ * Method dispatch table
+ */
+
+static PyMethodDef spoolss_methods[] = {
+
+ /* Open/close printer handles */
+
+ { "openprinter", (PyCFunction)spoolss_openprinter, METH_VARARGS | METH_KEYWORDS,
+ "Open a printer by name in UNC format.
+
+Optionally a dictionary of (domain, username, password) may be given in
+which case they are used when opening the RPC pipe. An access mask may
+also be given which defaults to MAXIMUM_ALLOWED_ACCESS.
+
+Example:
+
+>>> hnd = spoolss.openprinter(\"\\\\\\\\NPSD-PDC2\\\\meanie\")"},
+
+ { "closeprinter", spoolss_closeprinter, METH_VARARGS,
+ "Close a printer handle opened with openprinter or addprinter.
+
+Example:
+
+>>> spoolss.closeprinter(hnd)"},
+
+ { "addprinterex", (PyCFunction)spoolss_addprinterex, METH_VARARGS,
+ "addprinterex()"},
+
+ /* Server enumeratation functions */
+
+ { "enumprinters", (PyCFunction)spoolss_enumprinters,
+ METH_VARARGS | METH_KEYWORDS,
+ "Enumerate printers on a print server.
+
+Return a list of printers on a print server. The credentials, info level
+and flags may be specified as keyword arguments.
+
+Example:
+
+>>> print spoolss.enumprinters(\"\\\\\\\\npsd-pdc2\")
+[{'comment': 'i am a comment', 'printer_name': 'meanie', 'flags': 8388608,
+ 'description': 'meanie,Generic / Text Only,i am a location'},
+ {'comment': '', 'printer_name': 'fileprint', 'flags': 8388608,
+ 'description': 'fileprint,Generic / Text Only,'}]"},
+
+ { "enumports", (PyCFunction)spoolss_enumports,
+ METH_VARARGS | METH_KEYWORDS,
+ "Enumerate ports on a print server.
+
+Return a list of ports on a print server.
+
+Example:
+
+>>> print spoolss.enumports(\"\\\\\\\\npsd-pdc2\")
+[{'name': 'LPT1:'}, {'name': 'LPT2:'}, {'name': 'COM1:'}, {'name': 'COM2:'},
+ {'name': 'FILE:'}, {'name': '\\\\nautilus1\\zpekt3r'}]"},
+
+ { "enumprinterdrivers", (PyCFunction)spoolss_enumprinterdrivers,
+ METH_VARARGS | METH_KEYWORDS,
+ "Enumerate printer drivers on a print server.
+
+Return a list of printer drivers."},
+ /* Miscellaneous other commands */
+
+ { "getprinterdriverdir", (PyCFunction)spoolss_getprinterdriverdir,
+ METH_VARARGS | METH_KEYWORDS,
+ "Return printer driver directory.
+
+Return the printer driver directory for a given architecture. The
+architecture defaults to \"Windows NT x86\"."},
+
+ /* Other stuff - this should really go into a samba config module
+ but for the moment let's leave it here. */
+
+ { "setup_logging", (PyCFunction)py_setup_logging,
+ METH_VARARGS | METH_KEYWORDS,
+ "Set up debug logging.
+
+Initialises Samba's debug logging system. One argument is expected which
+is a boolean specifying whether debugging is interactive and sent to stdout
+or logged to a file.
+
+Example:
+
+>>> spoolss.setup_logging(interactive = 1)" },
+
+ { "get_debuglevel", (PyCFunction)get_debuglevel,
+ METH_VARARGS,
+ "Set the current debug level.
+
+Example:
+
+>>> spoolss.get_debuglevel()
+0" },
+
+ { "set_debuglevel", (PyCFunction)set_debuglevel,
+ METH_VARARGS,
+ "Get the current debug level.
+
+Example:
+
+>>> spoolss.set_debuglevel(10)" },
+
+ /* Printer driver routines */
+
+ { "addprinterdriver", (PyCFunction)spoolss_addprinterdriver,
+ METH_VARARGS | METH_KEYWORDS,
+ "Add a printer driver." },
+
+ { "addprinterdriverex", (PyCFunction)spoolss_addprinterdriverex,
+ METH_VARARGS | METH_KEYWORDS,
+ "Add a printer driver." },
+
+ { "deleteprinterdriver", (PyCFunction)spoolss_deleteprinterdriver,
+ METH_VARARGS | METH_KEYWORDS,
+ "Delete a printer driver." },
+
+ { "deleteprinterdriverex", (PyCFunction)spoolss_deleteprinterdriverex,
+ METH_VARARGS | METH_KEYWORDS,
+ "Delete a printer driver." },
+
+ { NULL }
+};
+
+/* Methods attached to a spoolss handle object */
+
+static PyMethodDef spoolss_hnd_methods[] = {
+
+ /* Printer info */
+
+ { "getprinter", (PyCFunction)spoolss_hnd_getprinter,
+ METH_VARARGS | METH_KEYWORDS,
+ "Get printer information.
+
+Return a dictionary of print information. The info level defaults to 1.
+
+Example:
+
+>>> hnd.getprinter()
+{'comment': 'i am a comment', 'printer_name': '\\\\NPSD-PDC2\\meanie',
+ 'description': '\\\\NPSD-PDC2\\meanie,Generic / Text Only,i am a location',
+ 'flags': 8388608}"},
+
+ { "setprinter", (PyCFunction)spoolss_hnd_setprinter,
+ METH_VARARGS | METH_KEYWORDS,
+ "Set printer information."},
+
+ /* Printer drivers */
+
+ { "getprinterdriver", (PyCFunction)spoolss_hnd_getprinterdriver,
+ METH_VARARGS | METH_KEYWORDS,
+ "Return printer driver information.
+
+Return a dictionary of printer driver information for the printer driver
+bound to this printer."},
+
+ /* Forms */
+
+ { "enumforms", (PyCFunction)spoolss_hnd_enumforms,
+ METH_VARARGS | METH_KEYWORDS,
+ "Enumerate supported forms.
+
+Return a list of forms supported by this printer or print server."},
+
+ { "setform", (PyCFunction)spoolss_hnd_setform,
+ METH_VARARGS | METH_KEYWORDS,
+ "Set form data.
+
+Set the form given by the dictionary argument."},
+
+ { "addform", (PyCFunction)spoolss_hnd_addform,
+ METH_VARARGS | METH_KEYWORDS,
+ "Add a new form." },
+
+ { "getform", (PyCFunction)spoolss_hnd_getform,
+ METH_VARARGS | METH_KEYWORDS,
+ "Get form properties." },
+
+ { "deleteform", (PyCFunction)spoolss_hnd_deleteform,
+ METH_VARARGS | METH_KEYWORDS,
+ "Delete a form." },
+
+ /* Job related methods */
+
+ { "enumjobs", (PyCFunction)spoolss_hnd_enumjobs,
+ METH_VARARGS | METH_KEYWORDS,
+ "Enumerate jobs." },
+
+ { "setjob", (PyCFunction)spoolss_hnd_setjob,
+ METH_VARARGS | METH_KEYWORDS,
+ "Set job information." },
+
+ { "getjob", (PyCFunction)spoolss_hnd_getjob,
+ METH_VARARGS | METH_KEYWORDS,
+ "Get job information." },
+
+ { "startpageprinter", (PyCFunction)spoolss_hnd_startpageprinter,
+ METH_VARARGS | METH_KEYWORDS,
+ "Notify spooler that a page is about to be printed." },
+
+ { "endpageprinter", (PyCFunction)spoolss_hnd_endpageprinter,
+ METH_VARARGS | METH_KEYWORDS,
+ "Notify spooler that a page is about to be printed." },
+
+ { "startdocprinter", (PyCFunction)spoolss_hnd_startdocprinter,
+ METH_VARARGS | METH_KEYWORDS,
+ "Notify spooler that a document is about to be printed." },
+
+ { "enddocprinter", (PyCFunction)spoolss_hnd_enddocprinter,
+ METH_VARARGS | METH_KEYWORDS,
+ "Notify spooler that a document is about to be printed." },
+
+ { "writeprinter", (PyCFunction)spoolss_hnd_writeprinter,
+ METH_VARARGS | METH_KEYWORDS,
+ "Write job data to a printer." },
+
+ { "addjob", (PyCFunction)spoolss_hnd_addjob,
+ METH_VARARGS | METH_KEYWORDS,
+ "Add a job to the list of print jobs." },
+
+ /* Printer data */
+
+ { "getprinterdata", (PyCFunction)spoolss_hnd_getprinterdata,
+ METH_VARARGS | METH_KEYWORDS,
+ "Get printer data." },
+
+ { "setprinterdata", (PyCFunction)spoolss_hnd_setprinterdata,
+ METH_VARARGS | METH_KEYWORDS,
+ "Set printer data." },
+
+ { "enumprinterdata", (PyCFunction)spoolss_hnd_enumprinterdata,
+ METH_VARARGS | METH_KEYWORDS,
+ "Enumerate printer data." },
+
+ { "deleteprinterdata", (PyCFunction)spoolss_hnd_deleteprinterdata,
+ METH_VARARGS | METH_KEYWORDS,
+ "Delete printer data." },
+
+ { "getprinterdataex", (PyCFunction)spoolss_hnd_getprinterdataex,
+ METH_VARARGS | METH_KEYWORDS,
+ "Get printer data." },
+
+ { "setprinterdataex", (PyCFunction)spoolss_hnd_setprinterdataex,
+ METH_VARARGS | METH_KEYWORDS,
+ "Set printer data." },
+
+ { "enumprinterdataex", (PyCFunction)spoolss_hnd_enumprinterdataex,
+ METH_VARARGS | METH_KEYWORDS,
+ "Enumerate printer data." },
+
+ { "deleteprinterdataex", (PyCFunction)spoolss_hnd_deleteprinterdataex,
+ METH_VARARGS | METH_KEYWORDS,
+ "Delete printer data." },
+
+ { "enumprinterkey", (PyCFunction)spoolss_hnd_enumprinterkey,
+ METH_VARARGS | METH_KEYWORDS,
+ "Enumerate printer key." },
+
+#if 0
+ /* Not implemented */
+
+ { "deleteprinterkey", (PyCFunction)spoolss_hnd_deleteprinterkey,
+ METH_VARARGS | METH_KEYWORDS,
+ "Delete printer key." },
+#endif
+
+ { NULL }
+
+};
+
+static void py_policy_hnd_dealloc(PyObject* self)
+{
+ spoolss_policy_hnd_object *hnd;
+
+ /* Close down policy handle and free talloc context */
+
+ hnd = (spoolss_policy_hnd_object*)self;
+
+ cli_shutdown(hnd->cli);
+ talloc_destroy(hnd->mem_ctx);
+
+ PyObject_Del(self);
+}
+
+static PyObject *py_policy_hnd_getattr(PyObject *self, char *attrname)
+{
+ return Py_FindMethod(spoolss_hnd_methods, self, attrname);
+}
+
+static char spoolss_type_doc[] =
+"Python wrapper for Windows NT SPOOLSS rpc pipe.";
+
+PyTypeObject spoolss_policy_hnd_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "spoolss.hnd",
+ sizeof(spoolss_policy_hnd_object),
+ 0,
+ py_policy_hnd_dealloc, /* tp_dealloc*/
+ 0, /* tp_print*/
+ py_policy_hnd_getattr, /* tp_getattr*/
+ 0, /* tp_setattr*/
+ 0, /* tp_compare*/
+ 0, /* tp_repr*/
+ 0, /* tp_as_number*/
+ 0, /* tp_as_sequence*/
+ 0, /* tp_as_mapping*/
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ spoolss_type_doc, /* tp_doc */
+};
+
+/* Initialise constants */
+
+static struct const_vals {
+ char *name;
+ uint32 value;
+} module_const_vals[] = {
+
+ /* Access permissions */
+
+ { "MAXIMUM_ALLOWED_ACCESS", MAXIMUM_ALLOWED_ACCESS },
+ { "SERVER_ALL_ACCESS", SERVER_ALL_ACCESS },
+ { "SERVER_READ", SERVER_READ },
+ { "SERVER_WRITE", SERVER_WRITE },
+ { "SERVER_EXECUTE", SERVER_EXECUTE },
+ { "SERVER_ACCESS_ADMINISTER", SERVER_ACCESS_ADMINISTER },
+ { "SERVER_ACCESS_ENUMERATE", SERVER_ACCESS_ENUMERATE },
+ { "PRINTER_ALL_ACCESS", PRINTER_ALL_ACCESS },
+ { "PRINTER_READ", PRINTER_READ },
+ { "PRINTER_WRITE", PRINTER_WRITE },
+ { "PRINTER_EXECUTE", PRINTER_EXECUTE },
+ { "PRINTER_ACCESS_ADMINISTER", PRINTER_ACCESS_ADMINISTER },
+ { "PRINTER_ACCESS_USE", PRINTER_ACCESS_USE },
+ { "JOB_ACCESS_ADMINISTER", JOB_ACCESS_ADMINISTER },
+ { "JOB_ALL_ACCESS", JOB_ALL_ACCESS },
+ { "JOB_READ", JOB_READ },
+ { "JOB_WRITE", JOB_WRITE },
+ { "JOB_EXECUTE", JOB_EXECUTE },
+ { "STANDARD_RIGHTS_ALL_ACCESS", STANDARD_RIGHTS_ALL_ACCESS },
+ { "STANDARD_RIGHTS_EXECUTE_ACCESS", STANDARD_RIGHTS_EXECUTE_ACCESS },
+ { "STANDARD_RIGHTS_READ_ACCESS", STANDARD_RIGHTS_READ_ACCESS },
+ { "STANDARD_RIGHTS_REQUIRED_ACCESS", STANDARD_RIGHTS_REQUIRED_ACCESS },
+ { "STANDARD_RIGHTS_WRITE_ACCESS", STANDARD_RIGHTS_WRITE_ACCESS },
+
+ /* Printer enumeration flags */
+
+ { "PRINTER_ENUM_DEFAULT", PRINTER_ENUM_DEFAULT },
+ { "PRINTER_ENUM_LOCAL", PRINTER_ENUM_LOCAL },
+ { "PRINTER_ENUM_CONNECTIONS", PRINTER_ENUM_CONNECTIONS },
+ { "PRINTER_ENUM_FAVORITE", PRINTER_ENUM_FAVORITE },
+ { "PRINTER_ENUM_NAME", PRINTER_ENUM_NAME },
+ { "PRINTER_ENUM_REMOTE", PRINTER_ENUM_REMOTE },
+ { "PRINTER_ENUM_SHARED", PRINTER_ENUM_SHARED },
+ { "PRINTER_ENUM_NETWORK", PRINTER_ENUM_NETWORK },
+
+ /* Form types */
+
+ { "FORM_USER", FORM_USER },
+ { "FORM_BUILTIN", FORM_BUILTIN },
+ { "FORM_PRINTER", FORM_PRINTER },
+
+ /* WERRORs */
+
+ { "WERR_OK", 0 },
+ { "WERR_BADFILE", 2 },
+ { "WERR_ACCESS_DENIED", 5 },
+ { "WERR_BADFID", 6 },
+ { "WERR_BADFUNC", 1 },
+ { "WERR_INSUFFICIENT_BUFFER", 122 },
+ { "WERR_NO_SUCH_SHARE", 67 },
+ { "WERR_ALREADY_EXISTS", 80 },
+ { "WERR_INVALID_PARAM", 87 },
+ { "WERR_NOT_SUPPORTED", 50 },
+ { "WERR_BAD_PASSWORD", 86 },
+ { "WERR_NOMEM", 8 },
+ { "WERR_INVALID_NAME", 123 },
+ { "WERR_UNKNOWN_LEVEL", 124 },
+ { "WERR_OBJECT_PATH_INVALID", 161 },
+ { "WERR_NO_MORE_ITEMS", 259 },
+ { "WERR_MORE_DATA", 234 },
+ { "WERR_UNKNOWN_PRINTER_DRIVER", 1797 },
+ { "WERR_INVALID_PRINTER_NAME", 1801 },
+ { "WERR_PRINTER_ALREADY_EXISTS", 1802 },
+ { "WERR_INVALID_DATATYPE", 1804 },
+ { "WERR_INVALID_ENVIRONMENT", 1805 },
+ { "WERR_INVALID_FORM_NAME", 1902 },
+ { "WERR_INVALID_FORM_SIZE", 1903 },
+ { "WERR_BUF_TOO_SMALL", 2123 },
+ { "WERR_JOB_NOT_FOUND", 2151 },
+ { "WERR_DEST_NOT_FOUND", 2152 },
+ { "WERR_NOT_LOCAL_DOMAIN", 2320 },
+ { "WERR_PRINTER_DRIVER_IN_USE", 3001 },
+ { "WERR_STATUS_MORE_ENTRIES ", 0x0105 },
+
+ /* Job control constants */
+
+ { "JOB_CONTROL_PAUSE", JOB_CONTROL_PAUSE },
+ { "JOB_CONTROL_RESUME", JOB_CONTROL_RESUME },
+ { "JOB_CONTROL_CANCEL", JOB_CONTROL_CANCEL },
+ { "JOB_CONTROL_RESTART", JOB_CONTROL_RESTART },
+ { "JOB_CONTROL_DELETE", JOB_CONTROL_DELETE },
+
+ { NULL },
+};
+
+static void const_init(PyObject *dict)
+{
+ struct const_vals *tmp;
+ PyObject *obj;
+
+ for (tmp = module_const_vals; tmp->name; tmp++) {
+ obj = PyInt_FromLong(tmp->value);
+ PyDict_SetItemString(dict, tmp->name, obj);
+ Py_DECREF(obj);
+ }
+}
+
+/* Module initialisation */
+
+void initspoolss(void)
+{
+ PyObject *module, *dict;
+
+ /* Initialise module */
+
+ module = Py_InitModule("spoolss", spoolss_methods);
+ dict = PyModule_GetDict(module);
+
+ /* Exceptions we can raise */
+
+ spoolss_error = PyErr_NewException("spoolss.error", NULL, NULL);
+ PyDict_SetItemString(dict, "error", spoolss_error);
+
+ spoolss_werror = PyErr_NewException("spoolss.werror", NULL, NULL);
+ PyDict_SetItemString(dict, "werror", spoolss_werror);
+
+ /* Initialise policy handle object */
+
+ spoolss_policy_hnd_type.ob_type = &PyType_Type;
+
+ PyDict_SetItemString(dict, "spoolss.hnd",
+ (PyObject *)&spoolss_policy_hnd_type);
+
+ /* Initialise constants */
+
+ const_init(dict);
+
+ /* Do samba initialisation */
+
+ py_samba_init();
+}
diff --git a/source4/python/py_spoolss.h b/source4/python/py_spoolss.h
new file mode 100644
index 0000000000..34b48190cd
--- /dev/null
+++ b/source4/python/py_spoolss.h
@@ -0,0 +1,160 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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.
+*/
+
+#ifndef _PY_SPOOLSS_H
+#define _PY_SPOOLSS_H
+
+#include "python/py_common.h"
+
+/* Spoolss policy handle object */
+
+typedef struct {
+ PyObject_HEAD
+ struct cli_state *cli;
+ TALLOC_CTX *mem_ctx;
+ POLICY_HND pol;
+} spoolss_policy_hnd_object;
+
+/* Exceptions raised by this module */
+
+extern PyTypeObject spoolss_policy_hnd_type;
+
+extern PyObject *spoolss_error, *spoolss_werror;
+
+/* The following definitions come from python/py_spoolss_common.c */
+
+PyObject *new_spoolss_policy_hnd_object(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, POLICY_HND *pol);
+
+/* The following definitions come from python/py_spoolss_drivers.c */
+
+PyObject *spoolss_enumprinterdrivers(PyObject *self, PyObject *args,
+ PyObject *kw);
+PyObject *spoolss_hnd_getprinterdriver(PyObject *self, PyObject *args,
+ PyObject *kw);
+PyObject *spoolss_getprinterdriverdir(PyObject *self, PyObject *args,
+ PyObject *kw);
+PyObject *spoolss_addprinterdriver(PyObject *self, PyObject *args,
+ PyObject *kw);
+PyObject *spoolss_addprinterdriverex(PyObject *self, PyObject *args,
+ PyObject *kw);
+PyObject *spoolss_deleteprinterdriver(PyObject *self, PyObject *args,
+ PyObject *kw);
+PyObject *spoolss_deleteprinterdriverex(PyObject *self, PyObject *args,
+ PyObject *kw);
+
+/* The following definitions come from python/py_spoolss_drivers_conv.c */
+
+BOOL py_from_DRIVER_INFO_1(PyObject **dict, DRIVER_INFO_1 *info);
+BOOL py_to_DRIVER_INFO_1(DRIVER_INFO_1 *info, PyObject *dict);
+BOOL py_from_DRIVER_INFO_2(PyObject **dict, DRIVER_INFO_2 *info);
+BOOL py_to_DRIVER_INFO_2(DRIVER_INFO_2 *info, PyObject *dict);
+BOOL py_from_DRIVER_INFO_3(PyObject **dict, DRIVER_INFO_3 *info);
+BOOL py_to_DRIVER_INFO_3(DRIVER_INFO_3 *info, PyObject *dict);
+BOOL py_from_DRIVER_INFO_6(PyObject **dict, DRIVER_INFO_6 *info);
+BOOL py_to_DRIVER_INFO_6(DRIVER_INFO_6 *info, PyObject *dict);
+BOOL py_from_DRIVER_DIRECTORY_1(PyObject **dict, DRIVER_DIRECTORY_1 *info);
+BOOL py_to_DRIVER_DIRECTORY_1(DRIVER_DIRECTORY_1 *info, PyObject *dict);
+
+/* The following definitions come from python/py_spoolss_forms.c */
+
+PyObject *spoolss_hnd_addform(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_getform(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_setform(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_deleteform(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_enumforms(PyObject *self, PyObject *args, PyObject *kw);
+
+/* The following definitions come from python/py_spoolss_forms_conv.c */
+
+BOOL py_from_FORM_1(PyObject **dict, FORM_1 *form);
+BOOL py_to_FORM(FORM *form, PyObject *dict);
+
+/* The following definitions come from python/py_spoolss_jobs.c */
+
+PyObject *spoolss_hnd_enumjobs(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_setjob(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_getjob(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_startpageprinter(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_endpageprinter(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_startdocprinter(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_enddocprinter(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_writeprinter(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_addjob(PyObject *self, PyObject *args, PyObject *kw);
+
+/* The following definitions come from python/py_spoolss_jobs_conv.c */
+
+BOOL py_from_JOB_INFO_1(PyObject **dict, JOB_INFO_1 *info);
+BOOL py_to_JOB_INFO_1(JOB_INFO_1 *info, PyObject *dict);
+BOOL py_from_JOB_INFO_2(PyObject **dict, JOB_INFO_2 *info);
+BOOL py_to_JOB_INFO_2(JOB_INFO_2 *info, PyObject *dict);
+BOOL py_from_DOC_INFO_1(PyObject **dict, DOC_INFO_1 *info);
+BOOL py_to_DOC_INFO_1(DOC_INFO_1 *info, PyObject *dict);
+
+/* The following definitions come from python/py_spoolss_ports.c */
+
+PyObject *spoolss_enumports(PyObject *self, PyObject *args, PyObject *kw);
+
+/* The following definitions come from python/py_spoolss_ports_conv.c */
+
+BOOL py_from_PORT_INFO_1(PyObject **dict, PORT_INFO_1 *info);
+BOOL py_to_PORT_INFO_1(PORT_INFO_1 *info, PyObject *dict);
+BOOL py_from_PORT_INFO_2(PyObject **dict, PORT_INFO_2 *info);
+BOOL py_to_PORT_INFO_2(PORT_INFO_2 *info, PyObject *dict);
+
+/* The following definitions come from python/py_spoolss_printerdata.c */
+
+PyObject *spoolss_hnd_getprinterdata(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_setprinterdata(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_enumprinterdata(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_deleteprinterdata(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_getprinterdataex(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_setprinterdataex(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_enumprinterdataex(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_deleteprinterdataex(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_enumprinterkey(PyObject *self, PyObject *args,
+ PyObject *kw);
+PyObject *spoolss_hnd_deleteprinterkey(PyObject *self, PyObject *args,
+ PyObject *kw);
+
+/* The following definitions come from python/py_spoolss_printers.c */
+
+PyObject *spoolss_openprinter(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_closeprinter(PyObject *self, PyObject *args);
+PyObject *spoolss_hnd_getprinter(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_hnd_setprinter(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_enumprinters(PyObject *self, PyObject *args, PyObject *kw);
+PyObject *spoolss_addprinterex(PyObject *self, PyObject *args, PyObject *kw);
+
+/* The following definitions come from python/py_spoolss_printers_conv.c */
+
+BOOL py_from_DEVICEMODE(PyObject **dict, DEVICEMODE *devmode);
+BOOL py_to_DEVICEMODE(DEVICEMODE *devmode, PyObject *dict);
+BOOL py_from_PRINTER_INFO_0(PyObject **dict, PRINTER_INFO_0 *info);
+BOOL py_to_PRINTER_INFO_0(PRINTER_INFO_0 *info, PyObject *dict);
+BOOL py_from_PRINTER_INFO_1(PyObject **dict, PRINTER_INFO_1 *info);
+BOOL py_to_PRINTER_INFO_1(PRINTER_INFO_1 *info, PyObject *dict);
+BOOL py_from_PRINTER_INFO_2(PyObject **dict, PRINTER_INFO_2 *info);
+BOOL py_to_PRINTER_INFO_2(PRINTER_INFO_2 *info, PyObject *dict,
+ TALLOC_CTX *mem_ctx);
+BOOL py_from_PRINTER_INFO_3(PyObject **dict, PRINTER_INFO_3 *info);
+BOOL py_to_PRINTER_INFO_3(PRINTER_INFO_3 *info, PyObject *dict,
+ TALLOC_CTX *mem_ctx);
+
+#endif /* _PY_SPOOLSS_H */
diff --git a/source4/python/py_spoolss_common.c b/source4/python/py_spoolss_common.c
new file mode 100644
index 0000000000..f34d2ac6c7
--- /dev/null
+++ b/source4/python/py_spoolss_common.c
@@ -0,0 +1,35 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2003
+
+ 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 "python/py_spoolss.h"
+
+PyObject *new_spoolss_policy_hnd_object(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, POLICY_HND *pol)
+{
+ spoolss_policy_hnd_object *o;
+
+ o = PyObject_New(spoolss_policy_hnd_object, &spoolss_policy_hnd_type);
+
+ o->cli = cli;
+ o->mem_ctx = mem_ctx;
+ memcpy(&o->pol, pol, sizeof(POLICY_HND));
+
+ return (PyObject*)o;
+}
diff --git a/source4/python/py_spoolss_drivers.c b/source4/python/py_spoolss_drivers.c
new file mode 100644
index 0000000000..a072ac0d5c
--- /dev/null
+++ b/source4/python/py_spoolss_drivers.c
@@ -0,0 +1,421 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+
+/* Enumerate printer drivers */
+
+PyObject *spoolss_enumprinterdrivers(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ WERROR werror;
+ PyObject *result = NULL, *creds = NULL;
+ PRINTER_DRIVER_CTR ctr;
+ int level = 1, i;
+ uint32 needed, num_drivers;
+ char *arch = "Windows NT x86", *server, *errstr;
+ static char *kwlist[] = {"server", "level", "creds", "arch", NULL};
+ struct cli_state *cli = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s|iOs", kwlist, &server, &level, &creds,
+ &arch))
+ return NULL;
+
+ if (server[0] != '\\' || server[1] != '\\') {
+ PyErr_SetString(PyExc_ValueError, "UNC name required");
+ return NULL;
+ }
+
+ server += 2;
+
+ if (creds && creds != Py_None && !PyDict_Check(creds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "credentials must be dictionary or None");
+ return NULL;
+ }
+
+ /* Call rpc function */
+
+ if (!(cli = open_pipe_creds(server, creds, PI_SPOOLSS, &errstr))) {
+ PyErr_SetString(spoolss_error, errstr);
+ free(errstr);
+ goto done;
+ }
+
+ if (!(mem_ctx = talloc_init("spoolss_enumprinterdrivers"))) {
+ PyErr_SetString(
+ spoolss_error, "unable to init talloc context\n");
+ goto done;
+ }
+
+ werror = cli_spoolss_enumprinterdrivers(
+ cli, mem_ctx, 0, &needed, level, arch,
+ &num_drivers, &ctr);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_enumprinterdrivers(
+ cli, mem_ctx, needed, NULL, level, arch,
+ &num_drivers, &ctr);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ goto done;
+ }
+
+ /* Return value */
+
+ switch (level) {
+ case 1:
+ result = PyDict_New();
+
+ for (i = 0; i < num_drivers; i++) {
+ PyObject *value;
+ fstring name;
+
+ rpcstr_pull(name, ctr.info1[i].name.buffer,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ py_from_DRIVER_INFO_1(&value, &ctr.info1[i]);
+
+ PyDict_SetItemString(result, name, value);
+ }
+
+ break;
+ case 2:
+ result = PyDict_New();
+
+ for(i = 0; i < num_drivers; i++) {
+ PyObject *value;
+ fstring name;
+
+ rpcstr_pull(name, ctr.info2[i].name.buffer,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ py_from_DRIVER_INFO_2(&value, &ctr.info2[i]);
+
+ PyDict_SetItemString(result, name, value);
+ }
+
+ break;
+ case 3:
+ result = PyDict_New();
+
+ for(i = 0; i < num_drivers; i++) {
+ PyObject *value;
+ fstring name;
+
+ rpcstr_pull(name, ctr.info3[i].name.buffer,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ py_from_DRIVER_INFO_3(&value, &ctr.info3[i]);
+
+ PyDict_SetItemString(result, name, value);
+ }
+
+ break;
+ case 6:
+ result = PyDict_New();
+
+ for(i = 0; i < num_drivers; i++) {
+ PyObject *value;
+ fstring name;
+
+ rpcstr_pull(name, ctr.info6[i].name.buffer,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ py_from_DRIVER_INFO_6(&value, &ctr.info6[i]);
+
+ PyList_SetItem(result, i, value);
+ }
+
+ break;
+ default:
+ PyErr_SetString(spoolss_error, "unknown info level");
+ goto done;
+ }
+
+ done:
+ if (cli)
+ cli_shutdown(cli);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
+
+/* Fetch printer driver */
+
+PyObject *spoolss_hnd_getprinterdriver(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ PyObject *result = Py_None;
+ PRINTER_DRIVER_CTR ctr;
+ int level = 1;
+ uint32 needed;
+ char *arch = "Windows NT x86";
+ static char *kwlist[] = {"level", "arch", NULL};
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "|is", kwlist, &level, &arch))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_getprinterdriver(
+ hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, level,
+ arch, &ctr);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_getprinterdriver(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
+ level, arch, &ctr);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ /* Return value */
+
+ switch (level) {
+ case 1:
+ py_from_DRIVER_INFO_1(&result, ctr.info1);
+ break;
+ case 2:
+ py_from_DRIVER_INFO_2(&result, ctr.info2);
+ break;
+ case 3:
+ py_from_DRIVER_INFO_3(&result, ctr.info3);
+ break;
+ case 6:
+ py_from_DRIVER_INFO_6(&result, ctr.info6);
+ break;
+ default:
+ PyErr_SetString(spoolss_error, "unsupported info level");
+ return NULL;
+ }
+
+ Py_INCREF(result);
+ return result;
+}
+
+/* Fetch printer driver directory */
+
+PyObject *spoolss_getprinterdriverdir(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ WERROR werror;
+ PyObject *result = NULL, *creds = NULL;
+ DRIVER_DIRECTORY_CTR ctr;
+ uint32 needed, level = 1;
+ char *arch = "Windows NT x86", *server, *errstr;
+ static char *kwlist[] = {"server", "level", "arch", "creds", NULL};
+ struct cli_state *cli = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s|isO", kwlist, &server, &level,
+ &arch, &creds))
+ return NULL;
+
+ if (server[0] != '\\' || server[1] != '\\') {
+ PyErr_SetString(PyExc_ValueError, "UNC name required");
+ return NULL;
+ }
+
+ server += 2;
+
+ if (creds && creds != Py_None && !PyDict_Check(creds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "credentials must be dictionary or None");
+ return NULL;
+ }
+
+ /* Call rpc function */
+
+ if (!(cli = open_pipe_creds(server, creds, PI_SPOOLSS, &errstr))) {
+ PyErr_SetString(spoolss_error, errstr);
+ free(errstr);
+ goto done;
+ }
+
+ if (!(mem_ctx = talloc_init("spoolss_getprinterdriverdir"))) {
+ PyErr_SetString(
+ spoolss_error, "unable to init talloc context\n");
+ goto done;
+ }
+
+ werror = cli_spoolss_getprinterdriverdir(
+ cli, mem_ctx, 0, &needed, level, arch, &ctr);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_getprinterdriverdir(
+ cli, mem_ctx, needed, NULL, level, arch, &ctr);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ goto done;
+ }
+
+ /* Return value */
+
+ switch (level) {
+ case 1:
+ py_from_DRIVER_DIRECTORY_1(&result, ctr.info1);
+ break;
+ default:
+ PyErr_SetString(spoolss_error, "unknown info level");
+ goto done;
+ }
+
+ done:
+ if (cli)
+ cli_shutdown(cli);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
+
+PyObject *spoolss_addprinterdriver(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ static char *kwlist[] = { "server", "info", "creds", NULL };
+ char *server, *errstr;
+ uint32 level;
+ PyObject *info, *result = NULL, *creds = NULL;
+ WERROR werror;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct cli_state *cli = NULL;
+ PRINTER_DRIVER_CTR ctr;
+ union {
+ DRIVER_INFO_3 driver_3;
+ } dinfo;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "sO!|O", kwlist, &server, &PyDict_Type,
+ &info, &creds))
+ return NULL;
+
+ if (server[0] == '\\' || server[1] == '\\')
+ server += 2;
+
+ if (creds && creds != Py_None && !PyDict_Check(creds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "credentials must be dictionary or None");
+ return NULL;
+ }
+
+ if (!(mem_ctx = talloc_init("spoolss_addprinterdriver"))) {
+ PyErr_SetString(
+ spoolss_error, "unable to init talloc context\n");
+ return NULL;
+ }
+
+ if (!(cli = open_pipe_creds(server, creds, PI_SPOOLSS, &errstr))) {
+ PyErr_SetString(spoolss_error, errstr);
+ free(errstr);
+ goto done;
+ }
+
+ if (!get_level_value(info, &level)) {
+ PyErr_SetString(spoolss_error, "invalid info level");
+ goto done;
+ }
+
+ if (level != 3) {
+ PyErr_SetString(spoolss_error, "unsupported info level");
+ goto done;
+ }
+
+ ZERO_STRUCT(ctr);
+ ZERO_STRUCT(dinfo);
+
+ switch(level) {
+ case 3:
+ ctr.info3 = &dinfo.driver_3;
+
+ if (!py_to_DRIVER_INFO_3(&dinfo.driver_3, info)) {
+ PyErr_SetString(spoolss_error,
+ "error converting to driver info 3");
+ goto done;
+ }
+
+ break;
+ default:
+ PyErr_SetString(spoolss_error, "unsupported info level");
+ goto done;
+ }
+
+ werror = cli_spoolss_addprinterdriver(cli, mem_ctx, level, &ctr);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ goto done;
+ }
+
+ Py_INCREF(Py_None);
+ result = Py_None;
+
+done:
+ if (cli)
+ cli_shutdown(cli);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return result;
+
+}
+
+PyObject *spoolss_addprinterdriverex(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ /* Not supported by Samba server */
+
+ PyErr_SetString(spoolss_error, "Not implemented");
+ return NULL;
+}
+
+PyObject *spoolss_deleteprinterdriver(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ PyErr_SetString(spoolss_error, "Not implemented");
+ return NULL;
+}
+
+PyObject *spoolss_deleteprinterdriverex(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ PyErr_SetString(spoolss_error, "Not implemented");
+ return NULL;
+}
diff --git a/source4/python/py_spoolss_drivers_conv.c b/source4/python/py_spoolss_drivers_conv.c
new file mode 100644
index 0000000000..9bc8408052
--- /dev/null
+++ b/source4/python/py_spoolss_drivers_conv.c
@@ -0,0 +1,179 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+#include "python/py_conv.h"
+
+/* Structure/hash conversions */
+
+struct pyconv py_DRIVER_INFO_1[] = {
+ { "name", PY_UNISTR, offsetof(DRIVER_INFO_1, name) },
+ { NULL }
+};
+
+struct pyconv py_DRIVER_INFO_2[] = {
+ { "version", PY_UINT32, offsetof(DRIVER_INFO_2, version) },
+ { "name", PY_UNISTR, offsetof(DRIVER_INFO_2, name) },
+ { "architecture", PY_UNISTR, offsetof(DRIVER_INFO_2, architecture) },
+ { "driver_path", PY_UNISTR, offsetof(DRIVER_INFO_2, driverpath) },
+ { "data_file", PY_UNISTR, offsetof(DRIVER_INFO_2, datafile) },
+ { "config_file", PY_UNISTR, offsetof(DRIVER_INFO_2, configfile) },
+ { NULL }
+};
+
+struct pyconv py_DRIVER_INFO_3[] = {
+ { "version", PY_UINT32, offsetof(DRIVER_INFO_3, version) },
+ { "name", PY_UNISTR, offsetof(DRIVER_INFO_3, name) },
+ { "architecture", PY_UNISTR, offsetof(DRIVER_INFO_3, architecture) },
+ { "driver_path", PY_UNISTR, offsetof(DRIVER_INFO_3, driverpath) },
+ { "data_file", PY_UNISTR, offsetof(DRIVER_INFO_3, datafile) },
+ { "config_file", PY_UNISTR, offsetof(DRIVER_INFO_3, configfile) },
+ { "help_file", PY_UNISTR, offsetof(DRIVER_INFO_3, helpfile) },
+ { "monitor_name", PY_UNISTR, offsetof(DRIVER_INFO_3, monitorname) },
+ { "default_datatype", PY_UNISTR, offsetof(DRIVER_INFO_3, defaultdatatype) },
+ { NULL }
+};
+
+struct pyconv py_DRIVER_INFO_6[] = {
+ { "version", PY_UINT32, offsetof(DRIVER_INFO_6, version) },
+ { "name", PY_UNISTR, offsetof(DRIVER_INFO_6, name) },
+ { "architecture", PY_UNISTR, offsetof(DRIVER_INFO_6, architecture) },
+ { "driver_path", PY_UNISTR, offsetof(DRIVER_INFO_6, driverpath) },
+ { "data_file", PY_UNISTR, offsetof(DRIVER_INFO_6, datafile) },
+ { "config_file", PY_UNISTR, offsetof(DRIVER_INFO_6, configfile) },
+ { "help_file", PY_UNISTR, offsetof(DRIVER_INFO_6, helpfile) },
+ { "monitor_name", PY_UNISTR, offsetof(DRIVER_INFO_6, monitorname) },
+ { "default_datatype", PY_UNISTR, offsetof(DRIVER_INFO_6, defaultdatatype) },
+ /* driver_date */
+ { "padding", PY_UINT32, offsetof(DRIVER_INFO_6, padding) },
+ { "driver_version_low", PY_UINT32, offsetof(DRIVER_INFO_6, driver_version_low) },
+ { "driver_version_high", PY_UINT32, offsetof(DRIVER_INFO_6, driver_version_high) },
+ { "mfg_name", PY_UNISTR, offsetof(DRIVER_INFO_6, mfgname) },
+ { "oem_url", PY_UNISTR, offsetof(DRIVER_INFO_6, oem_url) },
+ { "hardware_id", PY_UNISTR, offsetof(DRIVER_INFO_6, hardware_id) },
+ { "provider", PY_UNISTR, offsetof(DRIVER_INFO_6, provider) },
+
+ { NULL }
+};
+
+struct pyconv py_DRIVER_DIRECTORY_1[] = {
+ { "name", PY_UNISTR, offsetof(DRIVER_DIRECTORY_1, name) },
+ { NULL }
+};
+
+static uint16 *to_dependentfiles(PyObject *dict)
+{
+ return (uint16 *)"abcd\0";
+}
+
+BOOL py_from_DRIVER_INFO_1(PyObject **dict, DRIVER_INFO_1 *info)
+{
+ *dict = from_struct(info, py_DRIVER_INFO_1);
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(1));
+
+ return True;
+}
+
+BOOL py_to_DRIVER_INFO_1(DRIVER_INFO_1 *info, PyObject *dict)
+{
+ return False;
+}
+
+BOOL py_from_DRIVER_INFO_2(PyObject **dict, DRIVER_INFO_2 *info)
+{
+ *dict = from_struct(info, py_DRIVER_INFO_2);
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(2));
+
+ return True;
+}
+
+BOOL py_to_DRIVER_INFO_2(DRIVER_INFO_2 *info, PyObject *dict)
+{
+ return False;
+}
+
+BOOL py_from_DRIVER_INFO_3(PyObject **dict, DRIVER_INFO_3 *info)
+{
+ *dict = from_struct(info, py_DRIVER_INFO_3);
+
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(3));
+
+ PyDict_SetItemString(
+ *dict, "dependent_files",
+ from_unistr_list(info->dependentfiles));
+
+ return True;
+}
+
+BOOL py_to_DRIVER_INFO_3(DRIVER_INFO_3 *info, PyObject *dict)
+{
+ PyObject *obj, *dict_copy = PyDict_Copy(dict);
+ BOOL result = False;
+
+ if (!(obj = PyDict_GetItemString(dict_copy, "dependent_files")) ||
+ !PyList_Check(obj))
+ goto done;
+
+ info->dependentfiles = to_dependentfiles(obj);
+
+ PyDict_DelItemString(dict_copy, "dependent_files");
+
+ if (!(obj = PyDict_GetItemString(dict_copy, "level")) ||
+ !PyInt_Check(obj))
+ goto done;
+
+ PyDict_DelItemString(dict_copy, "level");
+
+ if (!to_struct(info, dict_copy, py_DRIVER_INFO_3))
+ goto done;
+
+ result = True;
+
+done:
+ Py_DECREF(dict_copy);
+ return result;
+}
+
+BOOL py_from_DRIVER_INFO_6(PyObject **dict, DRIVER_INFO_6 *info)
+{
+ *dict = from_struct(info, py_DRIVER_INFO_6);
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(6));
+ PyDict_SetItemString(
+ *dict, "dependent_files",
+ from_unistr_list(info->dependentfiles));
+ return True;
+}
+
+BOOL py_to_DRIVER_INFO_6(DRIVER_INFO_6 *info, PyObject *dict)
+{
+ return False;
+}
+
+BOOL py_from_DRIVER_DIRECTORY_1(PyObject **dict, DRIVER_DIRECTORY_1 *info)
+{
+ *dict = from_struct(info, py_DRIVER_DIRECTORY_1);
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(1));
+ return True;
+}
+
+BOOL py_to_DRIVER_DIRECTORY_1(DRIVER_DIRECTORY_1 *info, PyObject *dict)
+{
+ return False;
+}
diff --git a/source4/python/py_spoolss_forms.c b/source4/python/py_spoolss_forms.c
new file mode 100644
index 0000000000..ef9ed94533
--- /dev/null
+++ b/source4/python/py_spoolss_forms.c
@@ -0,0 +1,266 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+
+/* Add a form */
+
+PyObject *spoolss_hnd_addform(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ PyObject *info;
+ FORM form;
+ int level;
+ static char *kwlist[] = {"form", NULL};
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "O!", kwlist, &PyDict_Type, &info))
+ return NULL;
+
+ /* Call rpc function */
+
+ if (!py_to_FORM(&form, info)) {
+ PyErr_SetString(spoolss_error, "invalid form");
+ return NULL;
+ }
+
+ if (!get_level_value(info, &level)) {
+ PyErr_SetString(spoolss_error, "invalid info level");
+ return NULL;
+ }
+
+ if (level != 1) {
+ PyErr_SetString(spoolss_error, "unsupported info level");
+ return NULL;
+ }
+
+ switch (level) {
+ case 1: {
+ PyObject *obj = PyDict_GetItemString(info, "name");
+ char *form_name = PyString_AsString(obj);
+
+ init_unistr2(&form.name, form_name, strlen(form_name) + 1);
+ break;
+ }
+ default:
+ PyErr_SetString(spoolss_error, "unsupported info level");
+ return NULL;
+ }
+
+ werror = cli_spoolss_addform(hnd->cli, hnd->mem_ctx, &hnd->pol,
+ level, &form);
+
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Get form properties */
+
+PyObject *spoolss_hnd_getform(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ PyObject *result;
+ char *form_name;
+ int level = 1;
+ static char *kwlist[] = {"form_name", "level", NULL};
+ uint32 needed;
+ FORM_1 form;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s|i", kwlist, &form_name, &level))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_getform(hnd->cli, hnd->mem_ctx, 0, &needed,
+ &hnd->pol, form_name, level, &form);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_getform(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
+ form_name, 1, &form);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ result = Py_None;
+
+ switch(level) {
+ case 1:
+ py_from_FORM_1(&result, &form);
+ break;
+ }
+
+ Py_INCREF(result);
+ return result;
+}
+
+/* Set form properties */
+
+PyObject *spoolss_hnd_setform(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ PyObject *info, *form_name;
+ int level;
+ static char *kwlist[] = { "form", NULL};
+ FORM form;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "O!", kwlist, &PyDict_Type, &info))
+ return NULL;
+
+ if (!get_level_value(info, &level)) {
+ PyErr_SetString(spoolss_error, "invalid info level");
+ return NULL;
+ }
+
+ if (level != 1) {
+ PyErr_SetString(spoolss_error, "unsupported info level");
+ return NULL;
+ }
+
+ /* Call rpc function */
+
+ if (!py_to_FORM(&form, info)) {
+ PyErr_SetString(spoolss_error, "invalid form");
+ return NULL;
+ }
+
+ form_name = PyDict_GetItemString(info, "name");
+
+ werror = cli_spoolss_setform(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, level,
+ PyString_AsString(form_name), &form);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Delete a form */
+
+PyObject *spoolss_hnd_deleteform(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ static char *kwlist[] = {"form_name", NULL};
+ char *form_name;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s", kwlist, &form_name))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_deleteform(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, form_name);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Enumerate forms */
+
+PyObject *spoolss_hnd_enumforms(PyObject *self, PyObject *args, PyObject *kw)
+{
+ PyObject *result;
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ uint32 level = 1, num_forms, needed, i;
+ static char *kwlist[] = {"level", NULL};
+ FORM_1 *forms;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "|i", kwlist, &level))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_enumforms(
+ hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, level,
+ &num_forms, &forms);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_enumforms(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol, level,
+ &num_forms, &forms);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ switch(level) {
+ case 1:
+ result = PyDict_New();
+
+ for (i = 0; i < num_forms; i++) {
+ PyObject *value;
+ fstring name;
+
+ rpcstr_pull(name, forms[i].name.buffer,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ py_from_FORM_1(&value, &forms[i]);
+
+ PyDict_SetItemString(
+ value, "level", PyInt_FromLong(1));
+
+ PyDict_SetItemString(result, name, value);
+ }
+
+ break;
+ default:
+ PyErr_SetString(spoolss_error, "unknown info level");
+ return NULL;
+ }
+
+ return result;
+}
diff --git a/source4/python/py_spoolss_forms_conv.c b/source4/python/py_spoolss_forms_conv.c
new file mode 100644
index 0000000000..095a318fd2
--- /dev/null
+++ b/source4/python/py_spoolss_forms_conv.c
@@ -0,0 +1,91 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+#include "python/py_conv.h"
+
+struct pyconv py_FORM[] = {
+ { "flags", PY_UINT32, offsetof(FORM, flags) },
+ { "width", PY_UINT32, offsetof(FORM, size_x) },
+ { "length", PY_UINT32, offsetof(FORM, size_y) },
+ { "top", PY_UINT32, offsetof(FORM, top) },
+ { "left", PY_UINT32, offsetof(FORM, left) },
+ { "right", PY_UINT32, offsetof(FORM, right) },
+ { "bottom", PY_UINT32, offsetof(FORM, bottom) },
+ { NULL }
+};
+
+struct pyconv py_FORM_1[] = {
+ { "flags", PY_UINT32, offsetof(FORM_1, flag) },
+ { "width", PY_UINT32, offsetof(FORM_1, width) },
+ { "length", PY_UINT32, offsetof(FORM_1, length) },
+ { "top", PY_UINT32, offsetof(FORM_1, top) },
+ { "left", PY_UINT32, offsetof(FORM_1, left) },
+ { "right", PY_UINT32, offsetof(FORM_1, right) },
+ { "bottom", PY_UINT32, offsetof(FORM_1, bottom) },
+ { "name", PY_UNISTR, offsetof(FORM_1, name) },
+ { NULL }
+};
+
+BOOL py_from_FORM_1(PyObject **dict, FORM_1 *form)
+{
+ *dict = from_struct(form, py_FORM_1);
+
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(1));
+
+ return True;
+}
+
+BOOL py_to_FORM(FORM *form, PyObject *dict)
+{
+ PyObject *obj, *dict_copy = PyDict_Copy(dict);
+ char *name;
+ BOOL result = False;
+
+ if (!(obj = PyDict_GetItemString(dict_copy, "name")) ||
+ !PyString_Check(obj))
+ goto done;
+
+ PyDict_DelItemString(dict_copy, "name");
+
+ if (!(obj = PyDict_GetItemString(dict_copy, "level")) ||
+ !PyInt_Check(obj))
+ goto done;
+
+ PyDict_DelItemString(dict_copy, "level");
+
+ if (!to_struct(form, dict_copy, py_FORM))
+ goto done;
+
+ /* Careful! We can't call PyString_AsString(obj) then delete
+ obj and still expect to have our pointer pointing somewhere
+ useful. */
+
+ obj = PyDict_GetItemString(dict, "name");
+ name = PyString_AsString(obj);
+
+ init_unistr2(&form->name, name, strlen(name) + 1);
+
+ result = True;
+
+done:
+ Py_DECREF(dict_copy);
+ return result;
+}
diff --git a/source4/python/py_spoolss_jobs.c b/source4/python/py_spoolss_jobs.c
new file mode 100644
index 0000000000..59754bd36d
--- /dev/null
+++ b/source4/python/py_spoolss_jobs.c
@@ -0,0 +1,377 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+
+/* Enumerate jobs */
+
+PyObject *spoolss_hnd_enumjobs(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ PyObject *result;
+ int level = 1;
+ uint32 i, needed, num_jobs;
+ static char *kwlist[] = {"level", NULL};
+ JOB_INFO_CTR ctr;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "|i", kwlist, &level))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_enumjobs(
+ hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, level, 0,
+ 1000, &num_jobs, &ctr);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_enumjobs(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
+ level, 0, 1000, &num_jobs, &ctr);
+
+ /* Return value */
+
+ result = Py_None;
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ goto done;
+ }
+
+ result = PyList_New(num_jobs);
+
+ switch (level) {
+ case 1:
+ for (i = 0; i < num_jobs; i++) {
+ PyObject *value;
+
+ py_from_JOB_INFO_1(&value, &ctr.job.job_info_1[i]);
+
+ PyList_SetItem(result, i, value);
+ }
+
+ break;
+ case 2:
+ for(i = 0; i < num_jobs; i++) {
+ PyObject *value;
+
+ py_from_JOB_INFO_2(&value, &ctr.job.job_info_2[i]);
+
+ PyList_SetItem(result, i, value);
+ }
+
+ break;
+ }
+
+ done:
+ Py_INCREF(result);
+ return result;
+}
+
+/* Set job command */
+
+PyObject *spoolss_hnd_setjob(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ uint32 level = 0, command, jobid;
+ static char *kwlist[] = {"jobid", "command", "level", NULL};
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "ii|i", kwlist, &jobid, &command, &level))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_setjob(hnd->cli, hnd->mem_ctx, &hnd->pol,
+ jobid, level, command);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Get job */
+
+PyObject *spoolss_hnd_getjob(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ PyObject *result;
+ uint32 level = 1, jobid, needed;
+ static char *kwlist[] = {"jobid", "level", NULL};
+ JOB_INFO_CTR ctr;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "i|i", kwlist, &jobid, &level))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_getjob(hnd->cli, hnd->mem_ctx, 0, &needed,
+ &hnd->pol, jobid, level, &ctr);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_getjob(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
+ jobid, level, &ctr);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ switch(level) {
+ case 1:
+ py_from_JOB_INFO_1(&result, &ctr.job.job_info_1[0]);
+ break;
+ case 2:
+ py_from_JOB_INFO_2(&result, &ctr.job.job_info_2[0]);
+ break;
+ }
+
+ return result;
+}
+
+/* Start page printer. This notifies the spooler that a page is about to be
+ printed on the specified printer. */
+
+PyObject *spoolss_hnd_startpageprinter(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ static char *kwlist[] = { NULL };
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "", kwlist))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_startpageprinter(
+ hnd->cli, hnd->mem_ctx, &hnd->pol);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* End page printer. This notifies the spooler that a page has finished
+ being printed on the specified printer. */
+
+PyObject *spoolss_hnd_endpageprinter(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ static char *kwlist[] = { NULL };
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "", kwlist))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_endpageprinter(
+ hnd->cli, hnd->mem_ctx, &hnd->pol);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Start doc printer. This notifies the spooler that a document is about to be
+ printed on the specified printer. */
+
+PyObject *spoolss_hnd_startdocprinter(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ static char *kwlist[] = { "document_info", NULL };
+ PyObject *info, *obj;
+ uint32 level, jobid;
+ char *document_name = NULL, *output_file = NULL, *data_type = NULL;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "O!", kwlist, &PyDict_Type, &info))
+ return NULL;
+
+ /* Check document_info parameter */
+
+ if (!get_level_value(info, &level)) {
+ PyErr_SetString(spoolss_error, "invalid info level");
+ return NULL;
+ }
+
+ if (level != 1) {
+ PyErr_SetString(spoolss_error, "unsupported info level");
+ return NULL;
+ }
+
+ if ((obj = PyDict_GetItemString(info, "document_name"))) {
+
+ if (!PyString_Check(obj) && obj != Py_None) {
+ PyErr_SetString(spoolss_error,
+ "document_name not a string");
+ return NULL;
+ }
+
+ if (PyString_Check(obj))
+ document_name = PyString_AsString(obj);
+
+ } else {
+ PyErr_SetString(spoolss_error, "no document_name present");
+ return NULL;
+ }
+
+ if ((obj = PyDict_GetItemString(info, "output_file"))) {
+
+ if (!PyString_Check(obj) && obj != Py_None) {
+ PyErr_SetString(spoolss_error,
+ "output_file not a string");
+ return NULL;
+ }
+
+ if (PyString_Check(obj))
+ output_file = PyString_AsString(obj);
+
+ } else {
+ PyErr_SetString(spoolss_error, "no output_file present");
+ return NULL;
+ }
+
+ if ((obj = PyDict_GetItemString(info, "data_type"))) {
+
+ if (!PyString_Check(obj) && obj != Py_None) {
+ PyErr_SetString(spoolss_error,
+ "data_type not a string");
+ return NULL;
+ }
+
+ if (PyString_Check(obj))
+ data_type = PyString_AsString(obj);
+
+ } else {
+ PyErr_SetString(spoolss_error, "no data_type present");
+ return NULL;
+ }
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_startdocprinter(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, document_name,
+ output_file, data_type, &jobid);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ /* The return value is zero for an error (where does the status
+ code come from now??) and the return value is the jobid
+ allocated for the new job. */
+
+ return Py_BuildValue("i", jobid);
+}
+
+/* End doc printer. This notifies the spooler that a document has finished
+ being printed on the specified printer. */
+
+PyObject *spoolss_hnd_enddocprinter(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ static char *kwlist[] = { NULL };
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "", kwlist))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_enddocprinter(hnd->cli, hnd->mem_ctx, &hnd->pol);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Write data to a printer */
+
+PyObject *spoolss_hnd_writeprinter(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ static char *kwlist[] = { "data", NULL };
+ PyObject *data;
+ uint32 num_written;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "O!", kwlist, &PyString_Type, &data))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_writeprinter(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, PyString_Size(data),
+ PyString_AsString(data), &num_written);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject *spoolss_hnd_addjob(PyObject *self, PyObject *args, PyObject *kw)
+{
+ PyErr_SetString(spoolss_error, "Not implemented");
+ return NULL;
+}
diff --git a/source4/python/py_spoolss_jobs_conv.c b/source4/python/py_spoolss_jobs_conv.c
new file mode 100644
index 0000000000..cb04ec6713
--- /dev/null
+++ b/source4/python/py_spoolss_jobs_conv.c
@@ -0,0 +1,102 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+#include "python/py_conv.h"
+
+struct pyconv py_JOB_INFO_1[] = {
+ { "jobid", PY_UINT32, offsetof(JOB_INFO_1, jobid) },
+ { "printer_name", PY_UNISTR, offsetof(JOB_INFO_1, printername) },
+ { "server_name", PY_UNISTR, offsetof(JOB_INFO_1, machinename) },
+ { "user_name", PY_UNISTR, offsetof(JOB_INFO_1, username) },
+ { "document_name", PY_UNISTR, offsetof(JOB_INFO_1, document) },
+ { "data_type", PY_UNISTR, offsetof(JOB_INFO_1, datatype) },
+ { "text_status", PY_UNISTR, offsetof(JOB_INFO_1, text_status) },
+ { "status", PY_UINT32, offsetof(JOB_INFO_1, status) },
+ { "priority", PY_UINT32, offsetof(JOB_INFO_1, priority) },
+ { "position", PY_UINT32, offsetof(JOB_INFO_1, position) },
+ { "total_pages", PY_UINT32, offsetof(JOB_INFO_1, totalpages) },
+ { "pages_printed", PY_UINT32, offsetof(JOB_INFO_1, pagesprinted) },
+ { NULL }
+};
+
+struct pyconv py_JOB_INFO_2[] = {
+ { "jobid", PY_UINT32, offsetof(JOB_INFO_2, jobid) },
+ { "printer_name", PY_UNISTR, offsetof(JOB_INFO_2, printername) },
+ { "server_name", PY_UNISTR, offsetof(JOB_INFO_2, machinename) },
+ { "user_name", PY_UNISTR, offsetof(JOB_INFO_2, username) },
+ { "document_name", PY_UNISTR, offsetof(JOB_INFO_2, document) },
+ { "notify_name", PY_UNISTR, offsetof(JOB_INFO_2, notifyname) },
+ { "data_type", PY_UNISTR, offsetof(JOB_INFO_2, datatype) },
+ { "print_processor", PY_UNISTR, offsetof(JOB_INFO_2, printprocessor) },
+ { "parameters", PY_UNISTR, offsetof(JOB_INFO_2, parameters) },
+ { "driver_name", PY_UNISTR, offsetof(JOB_INFO_2, drivername) },
+ { "text_status", PY_UNISTR, offsetof(JOB_INFO_2, text_status) },
+ { "status", PY_UINT32, offsetof(JOB_INFO_2, status) },
+ { "priority", PY_UINT32, offsetof(JOB_INFO_2, priority) },
+ { "position", PY_UINT32, offsetof(JOB_INFO_2, position) },
+ { "start_time", PY_UINT32, offsetof(JOB_INFO_2, starttime) },
+ { "until_time", PY_UINT32, offsetof(JOB_INFO_2, untiltime) },
+ { "total_pages", PY_UINT32, offsetof(JOB_INFO_2, totalpages) },
+ { "size", PY_UINT32, offsetof(JOB_INFO_2, size) },
+ { "time_elapsed", PY_UINT32, offsetof(JOB_INFO_2, timeelapsed) },
+ { "pages_printed", PY_UINT32, offsetof(JOB_INFO_2, pagesprinted) },
+ { NULL }
+};
+
+struct pyconv py_DOC_INFO_1[] = {
+ { "document_name", PY_UNISTR, offsetof(DOC_INFO_1, docname) },
+ { "output_file", PY_UNISTR, offsetof(DOC_INFO_1, outputfile) },
+ { "data_type", PY_UNISTR, offsetof(DOC_INFO_1, datatype) },
+ { NULL }
+};
+
+BOOL py_from_JOB_INFO_1(PyObject **dict, JOB_INFO_1 *info)
+{
+ *dict = from_struct(info, py_JOB_INFO_1);
+ return True;
+}
+
+BOOL py_to_JOB_INFO_1(JOB_INFO_1 *info, PyObject *dict)
+{
+ return False;
+}
+
+BOOL py_from_JOB_INFO_2(PyObject **dict, JOB_INFO_2 *info)
+{
+ *dict = from_struct(info, py_JOB_INFO_2);
+ return True;
+}
+
+BOOL py_to_JOB_INFO_2(JOB_INFO_2 *info, PyObject *dict)
+{
+ return False;
+}
+
+BOOL py_from_DOC_INFO_1(PyObject **dict, DOC_INFO_1 *info)
+{
+ *dict = from_struct(info, py_DOC_INFO_1);
+ return True;
+}
+
+BOOL py_to_DOC_INFO_1(DOC_INFO_1 *info, PyObject *dict)
+{
+ return to_struct(info, dict, py_DOC_INFO_1);
+}
diff --git a/source4/python/py_spoolss_ports.c b/source4/python/py_spoolss_ports.c
new file mode 100644
index 0000000000..ddc8868f0f
--- /dev/null
+++ b/source4/python/py_spoolss_ports.c
@@ -0,0 +1,137 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+
+/* Enumerate ports */
+
+PyObject *spoolss_enumports(PyObject *self, PyObject *args, PyObject *kw)
+{
+ WERROR werror;
+ PyObject *result = NULL, *creds = NULL;
+ uint32 level = 1;
+ uint32 i, needed, num_ports;
+ static char *kwlist[] = {"server", "level", "creds", NULL};
+ TALLOC_CTX *mem_ctx = NULL;
+ struct cli_state *cli = NULL;
+ char *server, *errstr;
+ PORT_INFO_CTR ctr;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s|iO", kwlist, &server, &level, &creds))
+ return NULL;
+
+ if (server[0] != '\\' || server[1] != '\\') {
+ PyErr_SetString(PyExc_ValueError, "UNC name required");
+ return NULL;
+ }
+
+ server += 2;
+
+ if (creds && creds != Py_None && !PyDict_Check(creds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "credentials must be dictionary or None");
+ return NULL;
+ }
+
+ if (!(cli = open_pipe_creds(server, creds, PI_SPOOLSS, &errstr))) {
+ PyErr_SetString(spoolss_error, errstr);
+ free(errstr);
+ goto done;
+ }
+
+ if (!(mem_ctx = talloc_init("spoolss_enumports"))) {
+ PyErr_SetString(
+ spoolss_error, "unable to init talloc context\n");
+ goto done;
+ }
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_enum_ports(
+ cli, mem_ctx, 0, &needed, level, &num_ports, &ctr);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_enum_ports(
+ cli, mem_ctx, needed, NULL, level,
+ &num_ports, &ctr);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ goto done;
+ }
+
+ /* Return value */
+
+ switch (level) {
+ case 1:
+ result = PyDict_New();
+
+ for (i = 0; i < num_ports; i++) {
+ PyObject *value;
+ fstring name;
+
+ rpcstr_pull(name, ctr.port.info_1[i].port_name.buffer,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ py_from_PORT_INFO_1(&value, &ctr.port.info_1[i]);
+
+ PyDict_SetItemString(
+ value, "level", PyInt_FromLong(1));
+
+ PyDict_SetItemString(result, name, value);
+ }
+
+ break;
+ case 2:
+ result = PyDict_New();
+
+ for(i = 0; i < num_ports; i++) {
+ PyObject *value;
+ fstring name;
+
+ rpcstr_pull(name, ctr.port.info_2[i].port_name.buffer,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ py_from_PORT_INFO_2(&value, &ctr.port.info_2[i]);
+
+ PyDict_SetItemString(
+ value, "level", PyInt_FromLong(2));
+
+ PyDict_SetItemString(result, name, value);
+ }
+
+ break;
+ default:
+ PyErr_SetString(spoolss_error, "unknown info level");
+ goto done;
+ }
+
+ done:
+ if (cli)
+ cli_shutdown(cli);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
diff --git a/source4/python/py_spoolss_ports_conv.c b/source4/python/py_spoolss_ports_conv.c
new file mode 100644
index 0000000000..3f6d94bf7e
--- /dev/null
+++ b/source4/python/py_spoolss_ports_conv.c
@@ -0,0 +1,58 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+#include "python/py_conv.h"
+
+struct pyconv py_PORT_INFO_1[] = {
+ { "name", PY_UNISTR, offsetof(PORT_INFO_1, port_name) },
+ { NULL }
+};
+
+struct pyconv py_PORT_INFO_2[] = {
+ { "name", PY_UNISTR, offsetof(PORT_INFO_2, port_name) },
+ { "monitor_name", PY_UNISTR, offsetof(PORT_INFO_2, monitor_name) },
+ { "description", PY_UNISTR, offsetof(PORT_INFO_2, description) },
+ { "reserved", PY_UINT32, offsetof(PORT_INFO_2, reserved) },
+ { "type", PY_UINT32, offsetof(PORT_INFO_2, port_type) },
+ { NULL }
+};
+
+BOOL py_from_PORT_INFO_1(PyObject **dict, PORT_INFO_1 *info)
+{
+ *dict = from_struct(info, py_PORT_INFO_1);
+ return True;
+}
+
+BOOL py_to_PORT_INFO_1(PORT_INFO_1 *info, PyObject *dict)
+{
+ return False;
+}
+
+BOOL py_from_PORT_INFO_2(PyObject **dict, PORT_INFO_2 *info)
+{
+ *dict = from_struct(info, py_PORT_INFO_2);
+ return True;
+}
+
+BOOL py_to_PORT_INFO_2(PORT_INFO_2 *info, PyObject *dict)
+{
+ return False;
+}
diff --git a/source4/python/py_spoolss_printerdata.c b/source4/python/py_spoolss_printerdata.c
new file mode 100644
index 0000000000..f165475b08
--- /dev/null
+++ b/source4/python/py_spoolss_printerdata.c
@@ -0,0 +1,450 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+#include "python/py_conv.h"
+
+static BOOL py_from_printerdata(PyObject **dict, char *key, char *value,
+ uint16 data_type, uint8 *data,
+ uint32 data_size)
+{
+ *dict = PyDict_New();
+
+ PyDict_SetItemString(*dict, "key", Py_BuildValue("s", key ? key : ""));
+ PyDict_SetItemString(*dict, "value", Py_BuildValue("s", value));
+ PyDict_SetItemString(*dict, "type", Py_BuildValue("i", data_type));
+
+ PyDict_SetItemString(*dict, "data",
+ Py_BuildValue("s#", data, data_size));
+
+ return True;
+}
+
+static BOOL py_to_printerdata(char **key, char **value, uint16 *data_type,
+ uint8 **data, uint32 *data_size,
+ PyObject *dict)
+{
+ PyObject *obj;
+
+ if ((obj = PyDict_GetItemString(dict, "key"))) {
+
+ if (!PyString_Check(obj)) {
+ PyErr_SetString(spoolss_error,
+ "key not a string");
+ return False;
+ }
+
+ if (key) {
+ *key = PyString_AsString(obj);
+
+ if (!key[0])
+ *key = NULL;
+ }
+ } else
+ *key = NULL;
+
+ if ((obj = PyDict_GetItemString(dict, "value"))) {
+
+ if (!PyString_Check(obj)) {
+ PyErr_SetString(spoolss_error,
+ "value not a string");
+ return False;
+ }
+
+ *value = PyString_AsString(obj);
+ } else {
+ PyErr_SetString(spoolss_error, "no value present");
+ return False;
+ }
+
+ if ((obj = PyDict_GetItemString(dict, "type"))) {
+
+ if (!PyInt_Check(obj)) {
+ PyErr_SetString(spoolss_error,
+ "type not an integer");
+ return False;
+ }
+
+ *data_type = PyInt_AsLong(obj);
+ } else {
+ PyErr_SetString(spoolss_error, "no type present");
+ return False;
+ }
+
+ if ((obj = PyDict_GetItemString(dict, "data"))) {
+
+ if (!PyString_Check(obj)) {
+ PyErr_SetString(spoolss_error,
+ "data not a string");
+ return False;
+ }
+
+ *data = PyString_AsString(obj);
+ *data_size = PyString_Size(obj);
+ } else {
+ PyErr_SetString(spoolss_error, "no data present");
+ return False;
+ }
+
+ return True;
+}
+
+PyObject *spoolss_hnd_getprinterdata(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ static char *kwlist[] = { "value", NULL };
+ char *valuename;
+ WERROR werror;
+ uint32 needed;
+ PyObject *result;
+ REGISTRY_VALUE value;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "s", kwlist, &valuename))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_getprinterdata(
+ hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, valuename,
+ &value);
+
+ if (W_ERROR_V(werror) == ERRmoredata)
+ werror = cli_spoolss_getprinterdata(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
+ valuename, &value);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ py_from_printerdata(
+ &result, NULL, valuename, value.type, value.data_p,
+ value.size);
+
+ return result;
+}
+
+PyObject *spoolss_hnd_setprinterdata(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ static char *kwlist[] = { "data", NULL };
+ PyObject *py_data;
+ char *valuename;
+ WERROR werror;
+ REGISTRY_VALUE value;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "O!", kwlist, &PyDict_Type, &py_data))
+ return NULL;
+
+ if (!py_to_printerdata(
+ NULL, &valuename, &value.type, &value.data_p,
+ &value.size, py_data))
+ return NULL;
+
+ fstrcpy(value.valuename, valuename);
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_setprinterdata(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, &value);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject *spoolss_hnd_enumprinterdata(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ static char *kwlist[] = { NULL };
+ uint32 data_needed, value_needed, ndx = 0;
+ WERROR werror;
+ PyObject *result;
+ REGISTRY_VALUE value;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "", kwlist))
+ return NULL;
+
+ /* Get max buffer sizes for value and data */
+
+ werror = cli_spoolss_enumprinterdata(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, ndx, 0, 0,
+ &value_needed, &data_needed, NULL);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ /* Iterate over all printerdata */
+
+ result = PyDict_New();
+
+ while (W_ERROR_IS_OK(werror)) {
+ PyObject *obj;
+
+ werror = cli_spoolss_enumprinterdata(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, ndx,
+ value_needed, data_needed, NULL, NULL, &value);
+
+ if (py_from_printerdata(
+ &obj, NULL, value.valuename, value.type,
+ value.data_p, value.size))
+ PyDict_SetItemString(result, value.valuename, obj);
+
+ ndx++;
+ }
+
+ return result;
+}
+
+PyObject *spoolss_hnd_deleteprinterdata(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ static char *kwlist[] = { "value", NULL };
+ char *value;
+ WERROR werror;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "s", kwlist, &value))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_deleteprinterdata(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, value);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject *spoolss_hnd_getprinterdataex(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ static char *kwlist[] = { "key", "value", NULL };
+ char *key, *valuename;
+ WERROR werror;
+ uint32 needed;
+ PyObject *result;
+ REGISTRY_VALUE value;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "ss", kwlist, &key, &valuename))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_getprinterdataex(
+ hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, key,
+ valuename, &value);
+
+ if (W_ERROR_V(werror) == ERRmoredata)
+ werror = cli_spoolss_getprinterdataex(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol, key,
+ valuename, &value);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ py_from_printerdata(
+ &result, key, valuename, value.type, value.data_p, value.size);
+
+ return result;
+}
+
+PyObject *spoolss_hnd_setprinterdataex(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ static char *kwlist[] = { "data", NULL };
+ PyObject *py_data;
+ char *keyname, *valuename;
+ WERROR werror;
+ REGISTRY_VALUE value;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "O!", kwlist, &PyDict_Type, &py_data))
+ return NULL;
+
+ if (!py_to_printerdata(
+ &keyname, &valuename, &value.type, &value.data_p, &value.size, py_data))
+ return NULL;
+
+ fstrcpy(value.valuename, valuename);
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_setprinterdataex(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, keyname, &value);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject *spoolss_hnd_enumprinterdataex(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ static char *kwlist[] = { "key", NULL };
+ uint32 needed, i;
+ char *key;
+ WERROR werror;
+ PyObject *result;
+ REGVAL_CTR ctr;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "s", kwlist, &key))
+ return NULL;
+
+ /* Get max buffer sizes for value and data */
+
+ werror = cli_spoolss_enumprinterdataex(
+ hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, key, &ctr);
+
+ if (W_ERROR_V(werror) == ERRmoredata)
+ werror = cli_spoolss_enumprinterdataex(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol, key,
+ &ctr);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ /* Iterate over all printerdata */
+
+ result = PyDict_New();
+
+ for (i = 0; i < regval_ctr_numvals(&ctr); i++) {
+ REGISTRY_VALUE *value;
+ PyObject *item;
+
+ item = PyDict_New();
+ value = regval_ctr_specific_value(&ctr, i);
+
+ if (py_from_printerdata(
+ &item, key, value->valuename, value->type,
+ value->data_p, value->size))
+ PyDict_SetItemString(result, value->valuename, item);
+ }
+
+ return result;
+}
+
+PyObject *spoolss_hnd_deleteprinterdataex(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ static char *kwlist[] = { "key", "value", NULL };
+ char *key, *value;
+ WERROR werror;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "ss", kwlist, &key, &value))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_deleteprinterdataex(
+ hnd->cli, hnd->mem_ctx, &hnd->pol, key, value);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject *spoolss_hnd_enumprinterkey(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ static char *kwlist[] = { "key", NULL };
+ char *keyname;
+ WERROR werror;
+ uint32 needed, keylist_len;
+ uint16 *keylist;
+ PyObject *result;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "s", kwlist, &keyname))
+ return NULL;
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_enumprinterkey(
+ hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol,
+ keyname, &keylist, &keylist_len);
+
+ if (W_ERROR_V(werror) == ERRmoredata)
+ werror = cli_spoolss_enumprinterkey(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
+ keyname, &keylist, &keylist_len);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ result = from_unistr_list(keylist);
+
+ return result;
+}
+
+#if 0
+
+PyObject *spoolss_hnd_deleteprinterkey(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ static char *kwlist[] = { "key", NULL };
+ char *keyname;
+ WERROR werror;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "s", kwlist, &keyname))
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+#endif
diff --git a/source4/python/py_spoolss_printers.c b/source4/python/py_spoolss_printers.c
new file mode 100644
index 0000000000..d011681acc
--- /dev/null
+++ b/source4/python/py_spoolss_printers.c
@@ -0,0 +1,475 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+
+/* Open a printer */
+
+PyObject *spoolss_openprinter(PyObject *self, PyObject *args, PyObject *kw)
+{
+ char *unc_name, *server, *errstr;
+ TALLOC_CTX *mem_ctx = NULL;
+ POLICY_HND hnd;
+ WERROR werror;
+ PyObject *result = NULL, *creds = NULL;
+ static char *kwlist[] = { "printername", "creds", "access", NULL };
+ uint32 desired_access = MAXIMUM_ALLOWED_ACCESS;
+ struct cli_state *cli;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s|Oi", kwlist, &unc_name, &creds,
+ &desired_access))
+ return NULL;
+
+ if (unc_name[0] != '\\' || unc_name[1] != '\\') {
+ PyErr_SetString(PyExc_ValueError, "UNC name required");
+ return NULL;
+ }
+
+ server = strdup(unc_name + 2);
+
+ if (strchr(server, '\\')) {
+ char *c = strchr(server, '\\');
+ *c = 0;
+ }
+
+ if (creds && creds != Py_None && !PyDict_Check(creds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "credentials must be dictionary or None");
+ return NULL;
+ }
+
+ if (!(cli = open_pipe_creds(server, creds, PI_SPOOLSS, &errstr))) {
+ PyErr_SetString(spoolss_error, errstr);
+ free(errstr);
+ goto done;
+ }
+
+ if (!(mem_ctx = talloc_init("spoolss_openprinter"))) {
+ PyErr_SetString(spoolss_error,
+ "unable to init talloc context\n");
+ goto done;
+ }
+
+ werror = cli_spoolss_open_printer_ex(
+ cli, mem_ctx, unc_name, "", desired_access, server,
+ "", &hnd);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ goto done;
+ }
+
+ result = new_spoolss_policy_hnd_object(cli, mem_ctx, &hnd);
+
+ done:
+ if (!result) {
+ if (cli)
+ cli_shutdown(cli);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ }
+
+ SAFE_FREE(server);
+
+ return result;
+}
+
+/* Close a printer */
+
+PyObject *spoolss_closeprinter(PyObject *self, PyObject *args)
+{
+ PyObject *po;
+ spoolss_policy_hnd_object *hnd;
+ WERROR result;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTuple(args, "O!", &spoolss_policy_hnd_type, &po))
+ return NULL;
+
+ hnd = (spoolss_policy_hnd_object *)po;
+
+ /* Call rpc function */
+
+ result = cli_spoolss_close_printer(hnd->cli, hnd->mem_ctx, &hnd->pol);
+
+ /* Return value */
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Fetch printer information */
+
+PyObject *spoolss_hnd_getprinter(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ PyObject *result = NULL;
+ PRINTER_INFO_CTR ctr;
+ int level = 1;
+ uint32 needed;
+ static char *kwlist[] = {"level", NULL};
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "|i", kwlist, &level))
+ return NULL;
+
+ ZERO_STRUCT(ctr);
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_getprinter(
+ hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, level, &ctr);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_getprinter(
+ hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
+ level, &ctr);
+
+ /* Return value */
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ result = Py_None;
+
+ switch (level) {
+
+ case 0:
+ py_from_PRINTER_INFO_0(&result, ctr.printers_0);
+ break;
+
+ case 1:
+ py_from_PRINTER_INFO_1(&result, ctr.printers_1);
+ break;
+
+ case 2:
+ py_from_PRINTER_INFO_2(&result, ctr.printers_2);
+ break;
+
+ case 3:
+ py_from_PRINTER_INFO_3(&result, ctr.printers_3);
+ break;
+ }
+
+ Py_INCREF(result);
+ return result;
+}
+
+/* Set printer information */
+
+PyObject *spoolss_hnd_setprinter(PyObject *self, PyObject *args, PyObject *kw)
+{
+ spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
+ WERROR werror;
+ PyObject *info;
+ PRINTER_INFO_CTR ctr;
+ uint32 level;
+ static char *kwlist[] = {"dict", NULL};
+ union {
+ PRINTER_INFO_1 printers_1;
+ PRINTER_INFO_2 printers_2;
+ PRINTER_INFO_3 printers_3;
+ } pinfo;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "O!", kwlist, &PyDict_Type, &info))
+ return NULL;
+
+ if (!get_level_value(info, &level)) {
+ PyErr_SetString(spoolss_error, "invalid info level");
+ return NULL;
+ }
+
+ if (level < 1 && level > 3) {
+ PyErr_SetString(spoolss_error, "unsupported info level");
+ return NULL;
+ }
+
+ /* Fill in printer info */
+
+ ZERO_STRUCT(ctr);
+
+ switch (level) {
+ case 1:
+ ctr.printers_1 = &pinfo.printers_1;
+
+ if (!py_to_PRINTER_INFO_1(ctr.printers_1, info)){
+ PyErr_SetString(spoolss_error,
+ "error converting printer to info 1");
+ return NULL;
+ }
+
+ break;
+ case 2:
+ ctr.printers_2 = &pinfo.printers_2;
+
+ if (!py_to_PRINTER_INFO_2(ctr.printers_2, info,
+ hnd->mem_ctx)){
+ PyErr_SetString(spoolss_error,
+ "error converting printer to info 2");
+ return NULL;
+ }
+
+ break;
+ case 3:
+ ctr.printers_3 = &pinfo.printers_3;
+
+ if (!py_to_PRINTER_INFO_3(ctr.printers_3, info,
+ hnd->mem_ctx)) {
+ PyErr_SetString(spoolss_error,
+ "error converting to printer info 3");
+ return NULL;
+ }
+
+ break;
+ default:
+ PyErr_SetString(spoolss_error, "unsupported info level");
+ return NULL;
+ }
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_setprinter(hnd->cli, hnd->mem_ctx, &hnd->pol,
+ level, &ctr, 0);
+
+ /* Return value */
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Enumerate printers */
+
+PyObject *spoolss_enumprinters(PyObject *self, PyObject *args, PyObject *kw)
+{
+ WERROR werror;
+ PyObject *result = NULL, *creds = NULL;
+ PRINTER_INFO_CTR ctr;
+ int level = 1, flags = PRINTER_ENUM_LOCAL, i;
+ uint32 needed, num_printers;
+ static char *kwlist[] = {"server", "name", "level", "flags",
+ "creds", NULL};
+ TALLOC_CTX *mem_ctx = NULL;
+ struct cli_state *cli = NULL;
+ char *server, *errstr, *name = NULL;
+
+ /* Parse parameters */
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s|siiO", kwlist, &server, &name, &level,
+ &flags, &creds))
+ return NULL;
+
+ if (server[0] != '\\' || server[1] != '\\') {
+ PyErr_SetString(PyExc_ValueError, "UNC name required");
+ return NULL;
+ }
+
+ server += 2;
+
+ if (creds && creds != Py_None && !PyDict_Check(creds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "credentials must be dictionary or None");
+ return NULL;
+ }
+
+ if (!(cli = open_pipe_creds(server, creds, PI_SPOOLSS, &errstr))) {
+ PyErr_SetString(spoolss_error, errstr);
+ free(errstr);
+ goto done;
+ }
+
+ if (!(mem_ctx = talloc_init("spoolss_enumprinters"))) {
+ PyErr_SetString(
+ spoolss_error, "unable to init talloc context\n");
+ goto done;
+ }
+
+ /* This RPC is weird. By setting the server name to different
+ values we can get different behaviour. If however the server
+ name is not specified, we default it to being the full server
+ name as this is probably what the caller intended. To pass a
+ NULL name, pass a value of "" */
+
+ if (!name)
+ name = server;
+ else {
+ if (!name[0])
+ name = NULL;
+ }
+
+ /* Call rpc function */
+
+ werror = cli_spoolss_enum_printers(
+ cli, mem_ctx, 0, &needed, name, flags, level,
+ &num_printers, &ctr);
+
+ if (W_ERROR_V(werror) == ERRinsufficientbuffer)
+ werror = cli_spoolss_enum_printers(
+ cli, mem_ctx, needed, NULL, name, flags,
+ level, &num_printers, &ctr);
+
+ if (!W_ERROR_IS_OK(werror)) {
+ PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
+ goto done;
+ }
+
+ /* Return value */
+
+ switch (level) {
+ case 0:
+ result = PyDict_New();
+
+ for (i = 0; i < num_printers; i++) {
+ PyObject *value;
+ fstring s;
+
+ rpcstr_pull(s, ctr.printers_0[i].printername.buffer,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ py_from_PRINTER_INFO_0(&value, &ctr.printers_0[i]);
+
+ PyDict_SetItemString(
+ value, "level", PyInt_FromLong(0));
+
+ PyDict_SetItemString(result, s, value);
+ }
+
+ break;
+ case 1:
+ result = PyDict_New();
+
+ for(i = 0; i < num_printers; i++) {
+ PyObject *value;
+ fstring s;
+
+ rpcstr_pull(s, ctr.printers_1[i].name.buffer,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ py_from_PRINTER_INFO_1(&value, &ctr.printers_1[i]);
+
+ PyDict_SetItemString(
+ value, "level", PyInt_FromLong(1));
+
+ PyDict_SetItemString(result, s, value);
+ }
+
+ break;
+ case 2:
+ result = PyDict_New();
+
+ for(i = 0; i < num_printers; i++) {
+ PyObject *value;
+ fstring s;
+
+ rpcstr_pull(s, ctr.printers_2[i].printername.buffer,
+ sizeof(fstring), -1, STR_TERMINATE);
+
+ py_from_PRINTER_INFO_2(&value, &ctr.printers_2[i]);
+
+ PyDict_SetItemString(
+ value, "level", PyInt_FromLong(2));
+
+ PyDict_SetItemString(result, s, value);
+ }
+
+ break;
+ default:
+ PyErr_SetString(spoolss_error, "unknown info level");
+ goto done;
+ }
+
+done:
+ if (cli)
+ cli_shutdown(cli);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
+
+/* Add a printer */
+
+PyObject *spoolss_addprinterex(PyObject *self, PyObject *args, PyObject *kw)
+{
+ static char *kwlist[] = { "server", "printername", "info", "creds",
+ NULL};
+ char *printername, *server, *errstr;
+ PyObject *info, *result = NULL, *creds = NULL;
+ struct cli_state *cli = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+ PRINTER_INFO_CTR ctr;
+ PRINTER_INFO_2 info2;
+ WERROR werror;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "ssO!|O!", kwlist, &server, &printername,
+ &PyDict_Type, &info, &PyDict_Type, &creds))
+ return NULL;
+
+ if (!(cli = open_pipe_creds(server, creds, PI_SPOOLSS, &errstr))) {
+ PyErr_SetString(spoolss_error, errstr);
+ free(errstr);
+ goto done;
+ }
+
+ if (!(mem_ctx = talloc_init("spoolss_addprinterex"))) {
+ PyErr_SetString(
+ spoolss_error, "unable to init talloc context\n");
+ goto done;
+ }
+
+ if (!py_to_PRINTER_INFO_2(&info2, info, mem_ctx)) {
+ PyErr_SetString(spoolss_error,
+ "error converting to printer info 2");
+ goto done;
+ }
+
+ ctr.printers_2 = &info2;
+
+ werror = cli_spoolss_addprinterex(cli, mem_ctx, 2, &ctr);
+
+ Py_INCREF(Py_None);
+ result = Py_None;
+
+done:
+ if (cli)
+ cli_shutdown(cli);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
diff --git a/source4/python/py_spoolss_printers_conv.c b/source4/python/py_spoolss_printers_conv.c
new file mode 100644
index 0000000000..f7b2f516df
--- /dev/null
+++ b/source4/python/py_spoolss_printers_conv.c
@@ -0,0 +1,354 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_spoolss.h"
+#include "python/py_conv.h"
+
+struct pyconv py_PRINTER_INFO_0[] = {
+ { "name", PY_UNISTR, offsetof(PRINTER_INFO_0, printername) },
+ { "server_name", PY_UNISTR, offsetof(PRINTER_INFO_0, servername) },
+
+ { "cjobs", PY_UINT32, offsetof(PRINTER_INFO_0, cjobs) },
+ { "total_jobs", PY_UINT32, offsetof(PRINTER_INFO_0, total_jobs) },
+ { "total_bytes", PY_UINT32, offsetof(PRINTER_INFO_0, total_bytes) },
+
+ { "year", PY_UINT16, offsetof(PRINTER_INFO_0, year) },
+ { "month", PY_UINT16, offsetof(PRINTER_INFO_0, month) },
+ { "day_of_week", PY_UINT16, offsetof(PRINTER_INFO_0, dayofweek) },
+ { "day", PY_UINT16, offsetof(PRINTER_INFO_0, day) },
+ { "hour", PY_UINT16, offsetof(PRINTER_INFO_0, hour) },
+ { "minute", PY_UINT16, offsetof(PRINTER_INFO_0, minute) },
+ { "second", PY_UINT16, offsetof(PRINTER_INFO_0, second) },
+ { "milliseconds", PY_UINT16, offsetof(PRINTER_INFO_0, milliseconds) },
+
+ { "global_counter", PY_UINT32, offsetof(PRINTER_INFO_0, global_counter) },
+ { "total_pages", PY_UINT32, offsetof(PRINTER_INFO_0, total_pages) },
+
+ { "major_version", PY_UINT16, offsetof(PRINTER_INFO_0, major_version) },
+ { "build_version", PY_UINT16, offsetof(PRINTER_INFO_0, build_version) },
+
+ { "unknown7", PY_UINT32, offsetof(PRINTER_INFO_0, unknown7) },
+ { "unknown8", PY_UINT32, offsetof(PRINTER_INFO_0, unknown8) },
+ { "unknown9", PY_UINT32, offsetof(PRINTER_INFO_0, unknown9) },
+ { "session_counter", PY_UINT32, offsetof(PRINTER_INFO_0, session_counter)},
+ { "unknown11", PY_UINT32, offsetof(PRINTER_INFO_0, unknown11) },
+ { "printer_errors", PY_UINT32, offsetof(PRINTER_INFO_0, printer_errors) },
+ { "unknown13", PY_UINT32, offsetof(PRINTER_INFO_0, unknown13) },
+ { "unknown14", PY_UINT32, offsetof(PRINTER_INFO_0, unknown14) },
+ { "unknown15", PY_UINT32, offsetof(PRINTER_INFO_0, unknown15) },
+ { "unknown16", PY_UINT32, offsetof(PRINTER_INFO_0, unknown16) },
+ { "change_id", PY_UINT32, offsetof(PRINTER_INFO_0, change_id) },
+ { "unknown18", PY_UINT32, offsetof(PRINTER_INFO_0, unknown18) },
+ { "status", PY_UINT32, offsetof(PRINTER_INFO_0, status) },
+ { "unknown20", PY_UINT32, offsetof(PRINTER_INFO_0, unknown20) },
+ { "c_setprinter", PY_UINT32, offsetof(PRINTER_INFO_0, c_setprinter) },
+ { "unknown22", PY_UINT32, offsetof(PRINTER_INFO_0, unknown22) },
+ { "unknown23", PY_UINT32, offsetof(PRINTER_INFO_0, unknown23) },
+ { "unknown24", PY_UINT32, offsetof(PRINTER_INFO_0, unknown24) },
+ { "unknown25", PY_UINT32, offsetof(PRINTER_INFO_0, unknown25) },
+ { "unknown26", PY_UINT32, offsetof(PRINTER_INFO_0, unknown26) },
+ { "unknown27", PY_UINT32, offsetof(PRINTER_INFO_0, unknown27) },
+ { "unknown28", PY_UINT32, offsetof(PRINTER_INFO_0, unknown28) },
+ { "unknown29", PY_UINT32, offsetof(PRINTER_INFO_0, unknown29) },
+
+ { NULL }
+};
+
+struct pyconv py_PRINTER_INFO_1[] = {
+ { "name", PY_UNISTR, offsetof(PRINTER_INFO_1, name) },
+ { "description", PY_UNISTR, offsetof(PRINTER_INFO_1, description) },
+ { "comment", PY_UNISTR, offsetof(PRINTER_INFO_1, comment) },
+ { "flags", PY_UINT32, offsetof(PRINTER_INFO_1, flags) },
+ { NULL }
+};
+
+struct pyconv py_PRINTER_INFO_2[] = {
+ { "server_name", PY_UNISTR, offsetof(PRINTER_INFO_2, servername) },
+ { "name", PY_UNISTR, offsetof(PRINTER_INFO_2, printername) },
+ { "share_name", PY_UNISTR, offsetof(PRINTER_INFO_2, sharename) },
+ { "port_name", PY_UNISTR, offsetof(PRINTER_INFO_2, portname) },
+ { "driver_name", PY_UNISTR, offsetof(PRINTER_INFO_2, drivername) },
+ { "comment", PY_UNISTR, offsetof(PRINTER_INFO_2, comment) },
+ { "location", PY_UNISTR, offsetof(PRINTER_INFO_2, location) },
+ { "datatype", PY_UNISTR, offsetof(PRINTER_INFO_2, datatype) },
+ { "sepfile", PY_UNISTR, offsetof(PRINTER_INFO_2, sepfile) },
+ { "print_processor", PY_UNISTR, offsetof(PRINTER_INFO_2, printprocessor) },
+ { "parameters", PY_UNISTR, offsetof(PRINTER_INFO_2, parameters) },
+ { "attributes", PY_UINT32, offsetof(PRINTER_INFO_2, attributes) },
+ { "default_priority", PY_UINT32, offsetof(PRINTER_INFO_2, defaultpriority) },
+ { "priority", PY_UINT32, offsetof(PRINTER_INFO_2, priority) },
+ { "start_time", PY_UINT32, offsetof(PRINTER_INFO_2, starttime) },
+ { "until_time", PY_UINT32, offsetof(PRINTER_INFO_2, untiltime) },
+ { "status", PY_UINT32, offsetof(PRINTER_INFO_2, status) },
+ { "cjobs", PY_UINT32, offsetof(PRINTER_INFO_2, cjobs) },
+ { "average_ppm", PY_UINT32, offsetof(PRINTER_INFO_2, averageppm) },
+ { NULL }
+};
+
+struct pyconv py_PRINTER_INFO_3[] = {
+ { "flags", PY_UINT32, offsetof(PRINTER_INFO_3, flags) },
+ { NULL }
+};
+
+struct pyconv py_DEVICEMODE[] = {
+ { "device_name", PY_UNISTR, offsetof(DEVICEMODE, devicename) },
+ { "spec_version", PY_UINT16, offsetof(DEVICEMODE, specversion) },
+ { "driver_version", PY_UINT16, offsetof(DEVICEMODE, driverversion) },
+ { "size", PY_UINT16, offsetof(DEVICEMODE, size) },
+ { "fields", PY_UINT16, offsetof(DEVICEMODE, fields) },
+ { "orientation", PY_UINT16, offsetof(DEVICEMODE, orientation) },
+ { "paper_size", PY_UINT16, offsetof(DEVICEMODE, papersize) },
+ { "paper_width", PY_UINT16, offsetof(DEVICEMODE, paperwidth) },
+ { "paper_length", PY_UINT16, offsetof(DEVICEMODE, paperlength) },
+ { "scale", PY_UINT16, offsetof(DEVICEMODE, scale) },
+ { "copies", PY_UINT16, offsetof(DEVICEMODE, copies) },
+ { "default_source", PY_UINT16, offsetof(DEVICEMODE, defaultsource) },
+ { "print_quality", PY_UINT16, offsetof(DEVICEMODE, printquality) },
+ { "color", PY_UINT16, offsetof(DEVICEMODE, color) },
+ { "duplex", PY_UINT16, offsetof(DEVICEMODE, duplex) },
+ { "y_resolution", PY_UINT16, offsetof(DEVICEMODE, yresolution) },
+ { "tt_option", PY_UINT16, offsetof(DEVICEMODE, ttoption) },
+ { "collate", PY_UINT16, offsetof(DEVICEMODE, collate) },
+ { "form_name", PY_UNISTR, offsetof(DEVICEMODE, formname) },
+ { "log_pixels", PY_UINT16, offsetof(DEVICEMODE, logpixels) },
+ { "bits_per_pel", PY_UINT32, offsetof(DEVICEMODE, bitsperpel) },
+ { "pels_width", PY_UINT32, offsetof(DEVICEMODE, pelswidth) },
+ { "pels_height", PY_UINT32, offsetof(DEVICEMODE, pelsheight) },
+ { "display_flags", PY_UINT32, offsetof(DEVICEMODE, displayflags) },
+ { "display_frequency", PY_UINT32, offsetof(DEVICEMODE, displayfrequency) },
+ { "icm_method", PY_UINT32, offsetof(DEVICEMODE, icmmethod) },
+ { "icm_intent", PY_UINT32, offsetof(DEVICEMODE, icmintent) },
+ { "media_type", PY_UINT32, offsetof(DEVICEMODE, mediatype) },
+ { "dither_type", PY_UINT32, offsetof(DEVICEMODE, dithertype) },
+ { "reserved1", PY_UINT32, offsetof(DEVICEMODE, reserved1) },
+ { "reserved2", PY_UINT32, offsetof(DEVICEMODE, reserved2) },
+ { "panning_width", PY_UINT32, offsetof(DEVICEMODE, panningwidth) },
+ { "panning_height", PY_UINT32, offsetof(DEVICEMODE, panningheight) },
+ { NULL }
+};
+
+/*
+ * Convert between DEVICEMODE and Python
+ */
+
+BOOL py_from_DEVICEMODE(PyObject **dict, DEVICEMODE *devmode)
+{
+ *dict = from_struct(devmode, py_DEVICEMODE);
+
+ PyDict_SetItemString(*dict, "private",
+ PyString_FromStringAndSize(
+ devmode->private, devmode->driverextra));
+
+ return True;
+}
+
+BOOL py_to_DEVICEMODE(DEVICEMODE *devmode, PyObject *dict)
+{
+ PyObject *obj, *dict_copy = PyDict_Copy(dict);
+ BOOL result = False;
+
+ if (!(obj = PyDict_GetItemString(dict_copy, "private")))
+ goto done;
+
+ if (!PyString_Check(obj))
+ goto done;
+
+ devmode->private = PyString_AsString(obj);
+ devmode->driverextra = PyString_Size(obj);
+
+ PyDict_DelItemString(dict_copy, "private");
+
+ if (!to_struct(devmode, dict_copy, py_DEVICEMODE))
+ goto done;
+
+ result = True;
+
+done:
+ Py_DECREF(dict_copy);
+ return result;
+}
+
+/*
+ * Convert between PRINTER_INFO_0 and Python
+ */
+
+BOOL py_from_PRINTER_INFO_0(PyObject **dict, PRINTER_INFO_0 *info)
+{
+ *dict = from_struct(info, py_PRINTER_INFO_0);
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(0));
+ return True;
+}
+
+BOOL py_to_PRINTER_INFO_0(PRINTER_INFO_0 *info, PyObject *dict)
+{
+ return False;
+}
+
+/*
+ * Convert between PRINTER_INFO_1 and Python
+ */
+
+BOOL py_from_PRINTER_INFO_1(PyObject **dict, PRINTER_INFO_1 *info)
+{
+ *dict = from_struct(info, py_PRINTER_INFO_1);
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(1));
+ return True;
+}
+
+BOOL py_to_PRINTER_INFO_1(PRINTER_INFO_1 *info, PyObject *dict)
+{
+ PyObject *obj, *dict_copy = PyDict_Copy(dict);
+ BOOL result = False;
+
+ if (!(obj = PyDict_GetItemString(dict_copy, "level")) ||
+ !PyInt_Check(obj))
+ goto done;
+
+ PyDict_DelItemString(dict_copy, "level");
+
+ if (!to_struct(info, dict_copy, py_PRINTER_INFO_1))
+ goto done;
+
+ result = True;
+
+done:
+ Py_DECREF(dict_copy);
+ return result;
+}
+
+/*
+ * Convert between PRINTER_INFO_2 and Python
+ */
+
+BOOL py_from_PRINTER_INFO_2(PyObject **dict, PRINTER_INFO_2 *info)
+{
+ PyObject *obj;
+
+ *dict = from_struct(info, py_PRINTER_INFO_2);
+
+ /* The security descriptor could be NULL */
+
+ if (info->secdesc) {
+ if (py_from_SECDESC(&obj, info->secdesc))
+ PyDict_SetItemString(*dict, "security_descriptor", obj);
+ }
+
+ /* Bong! The devmode could be NULL */
+
+ if (info->devmode)
+ py_from_DEVICEMODE(&obj, info->devmode);
+ else
+ obj = PyDict_New();
+
+ PyDict_SetItemString(*dict, "device_mode", obj);
+
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(2));
+
+ return True;
+}
+
+BOOL py_to_PRINTER_INFO_2(PRINTER_INFO_2 *info, PyObject *dict,
+ TALLOC_CTX *mem_ctx)
+{
+ PyObject *obj, *dict_copy = PyDict_Copy(dict);
+ BOOL result = False;
+
+ /* Convert security descriptor - may be NULL */
+
+ info->secdesc = NULL;
+
+ if ((obj = PyDict_GetItemString(dict_copy, "security_descriptor"))) {
+
+ if (!PyDict_Check(obj))
+ goto done;
+
+ if (!py_to_SECDESC(&info->secdesc, obj, mem_ctx))
+ goto done;
+
+ PyDict_DelItemString(dict_copy, "security_descriptor");
+ }
+
+ /* Convert device mode */
+
+ if (!(obj = PyDict_GetItemString(dict_copy, "device_mode"))
+ || !PyDict_Check(obj))
+ goto done;
+
+ info->devmode = talloc(mem_ctx, sizeof(DEVICEMODE));
+
+ if (!py_to_DEVICEMODE(info->devmode, obj))
+ goto done;
+
+ PyDict_DelItemString(dict_copy, "device_mode");
+
+ /* Check info level */
+
+ if (!(obj = PyDict_GetItemString(dict_copy, "level")) ||
+ !PyInt_Check(obj))
+ goto done;
+
+ PyDict_DelItemString(dict_copy, "level");
+
+ /* Convert remaining elements of dictionary */
+
+ if (!to_struct(info, dict_copy, py_PRINTER_INFO_2))
+ goto done;
+
+ result = True;
+
+done:
+ Py_DECREF(dict_copy);
+ return result;
+}
+
+/*
+ * Convert between PRINTER_INFO_1 and Python
+ */
+
+BOOL py_from_PRINTER_INFO_3(PyObject **dict, PRINTER_INFO_3 *info)
+{
+ PyObject *obj;
+
+ *dict = from_struct(info, py_PRINTER_INFO_3);
+
+ if (py_from_SECDESC(&obj, info->secdesc))
+ PyDict_SetItemString(*dict, "security_descriptor", obj);
+
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(3));
+
+ return True;
+}
+
+BOOL py_to_PRINTER_INFO_3(PRINTER_INFO_3 *info, PyObject *dict,
+ TALLOC_CTX *mem_ctx)
+{
+ PyObject *obj;
+
+ if (!to_struct(info, dict, py_PRINTER_INFO_3))
+ return False;
+
+ if (!(obj = PyDict_GetItemString(dict, "security_descriptor")))
+ return False;
+
+ if (!py_to_SECDESC(&info->secdesc, obj, mem_ctx))
+ return False;
+
+ return True;
+}
diff --git a/source4/python/py_srvsvc.c b/source4/python/py_srvsvc.c
new file mode 100644
index 0000000000..8ec2430285
--- /dev/null
+++ b/source4/python/py_srvsvc.c
@@ -0,0 +1,215 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2003
+
+ 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 "python/py_srvsvc.h"
+
+/* Exceptions this module can raise */
+
+PyObject *srvsvc_error, *srvsvc_werror;
+
+static struct const_vals {
+ char *name;
+ uint32 value;
+} module_const_vals[] = {
+ { "SV_TYPE_WORKSTATION", SV_TYPE_WORKSTATION },
+ { "SV_TYPE_SERVER", SV_TYPE_SERVER },
+ { "SV_TYPE_SQLSERVER", SV_TYPE_SQLSERVER },
+ { "SV_TYPE_DOMAIN_CTRL", SV_TYPE_DOMAIN_CTRL },
+ { "SV_TYPE_DOMAIN_BAKCTRL", SV_TYPE_DOMAIN_BAKCTRL },
+ { "SV_TYPE_TIME_SOURCE", SV_TYPE_TIME_SOURCE },
+ { "SV_TYPE_AFP", SV_TYPE_AFP },
+ { "SV_TYPE_NOVELL", SV_TYPE_NOVELL },
+ { "SV_TYPE_DOMAIN_MEMBER", SV_TYPE_DOMAIN_MEMBER },
+ { "SV_TYPE_PRINTQ_SERVER", SV_TYPE_PRINTQ_SERVER },
+ { "SV_TYPE_DIALIN_SERVER", SV_TYPE_DIALIN_SERVER },
+ { "SV_TYPE_SERVER_UNIX", SV_TYPE_SERVER_UNIX },
+ { "SV_TYPE_NT", SV_TYPE_NT },
+ { "SV_TYPE_WFW", SV_TYPE_WFW },
+ { "SV_TYPE_SERVER_MFPN", SV_TYPE_SERVER_MFPN },
+ { "SV_TYPE_SERVER_NT", SV_TYPE_SERVER_NT },
+ { "SV_TYPE_POTENTIAL_BROWSER", SV_TYPE_POTENTIAL_BROWSER },
+ { "SV_TYPE_BACKUP_BROWSER", SV_TYPE_BACKUP_BROWSER },
+ { "SV_TYPE_MASTER_BROWSER", SV_TYPE_MASTER_BROWSER },
+ { "SV_TYPE_DOMAIN_MASTER", SV_TYPE_DOMAIN_MASTER },
+ { "SV_TYPE_SERVER_OSF", SV_TYPE_SERVER_OSF },
+ { "SV_TYPE_SERVER_VMS", SV_TYPE_SERVER_VMS },
+ { "SV_TYPE_WIN95_PLUS", SV_TYPE_WIN95_PLUS },
+ { "SV_TYPE_DFS_SERVER", SV_TYPE_DFS_SERVER },
+ { "SV_TYPE_ALTERNATE_XPORT", SV_TYPE_ALTERNATE_XPORT },
+ { "SV_TYPE_LOCAL_LIST_ONLY", SV_TYPE_LOCAL_LIST_ONLY },
+ { "SV_TYPE_DOMAIN_ENUM", SV_TYPE_DOMAIN_ENUM },
+ { NULL },
+};
+
+static void const_init(PyObject *dict)
+{
+ struct const_vals *tmp;
+ PyObject *obj;
+
+ for (tmp = module_const_vals; tmp->name; tmp++) {
+ obj = PyInt_FromLong(tmp->value);
+ PyDict_SetItemString(dict, tmp->name, obj);
+ Py_DECREF(obj);
+ }
+}
+
+/* NetServerGetInfo */
+
+PyObject *srvsvc_netservergetinfo(PyObject *self, PyObject *args,
+ PyObject *kw)
+{
+ static char *kwlist[] = { "server", "level", "creds", NULL };
+ char *unc_name, *server, *errstr;
+ PyObject *creds = NULL, *result = NULL;
+ struct cli_state *cli;
+ TALLOC_CTX *mem_ctx = NULL;
+ uint32 level;
+ SRV_INFO_CTR ctr;
+ WERROR status;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "si|O", kwlist, &unc_name, &level, &creds))
+ return NULL;
+
+ if (unc_name[0] != '\\' || unc_name[1] != '\\') {
+ PyErr_SetString(PyExc_ValueError, "UNC name required");
+ return NULL;
+ }
+
+ server = strdup(unc_name + 2);
+
+ if (strchr(server, '\\')) {
+ char *c = strchr(server, '\\');
+ *c = 0;
+ }
+
+ if (creds && creds != Py_None && !PyDict_Check(creds)) {
+ PyErr_SetString(PyExc_TypeError,
+ "credentials must be dictionary or None");
+ return NULL;
+ }
+
+ if (!(cli = open_pipe_creds(server, creds, PI_SRVSVC, &errstr))) {
+ PyErr_SetString(srvsvc_error, errstr);
+ free(errstr);
+ goto done;
+ }
+
+ if (!(mem_ctx = talloc_init("srvsvc_netservergetinfo"))) {
+ PyErr_SetString(srvsvc_error,
+ "unable to init talloc context\n");
+ goto done;
+ }
+
+ ZERO_STRUCT(ctr);
+
+ status = cli_srvsvc_net_srv_get_info(cli, mem_ctx, level, &ctr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_SetObject(srvsvc_error, py_werror_tuple(status));
+ goto done;
+ }
+
+ if (level != ctr.switch_value) {
+ PyErr_SetString(srvsvc_error, "container level value wrong");
+ goto done;
+ }
+
+ switch(level) {
+ case 101:
+ py_from_SRV_INFO_101(&result, &ctr.srv.sv101);
+ break;
+ }
+
+ Py_INCREF(result);
+
+done:
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
+
+/*
+ * Module initialisation
+ */
+
+static PyMethodDef srvsvc_methods[] = {
+ { "netservergetinfo", (PyCFunction)srvsvc_netservergetinfo,
+ METH_VARARGS | METH_KEYWORDS,
+ "Retrieve information about a particular server." },
+
+ { "setup_logging", (PyCFunction)py_setup_logging,
+ METH_VARARGS | METH_KEYWORDS,
+ "Set up debug logging.
+
+Initialises Samba's debug logging system. One argument is expected which
+is a boolean specifying whether debugging is interactive and sent to stdout
+or logged to a file.
+
+Example:
+
+>>> srvsvc.setup_logging(interactive = 1)" },
+
+ { "get_debuglevel", (PyCFunction)get_debuglevel,
+ METH_VARARGS,
+ "Set the current debug level.
+
+Example:
+
+>>> srvsvc.get_debuglevel()
+0" },
+
+ { "set_debuglevel", (PyCFunction)set_debuglevel,
+ METH_VARARGS,
+ "Get the current debug level.
+
+Example:
+
+>>> srvsvc.set_debuglevel(10)" },
+
+ { NULL }
+};
+
+void initsrvsvc(void)
+{
+ PyObject *module, *dict;
+
+ /* Initialise module */
+
+ module = Py_InitModule("srvsvc", srvsvc_methods);
+ dict = PyModule_GetDict(module);
+
+ /* Exceptions we can raise */
+
+ srvsvc_error = PyErr_NewException("srvsvc.error", NULL, NULL);
+ PyDict_SetItemString(dict, "error", srvsvc_error);
+
+ srvsvc_werror = PyErr_NewException("srvsvc.werror", NULL, NULL);
+ PyDict_SetItemString(dict, "werror", srvsvc_werror);
+
+ /* Initialise constants */
+
+ const_init(dict);
+
+ /* Do samba initialisation */
+
+ py_samba_init();
+}
diff --git a/source4/python/py_srvsvc.h b/source4/python/py_srvsvc.h
new file mode 100644
index 0000000000..b440c32e13
--- /dev/null
+++ b/source4/python/py_srvsvc.h
@@ -0,0 +1,26 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2003
+
+ 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.
+*/
+
+#ifndef _PY_SRVSVC_H
+#define _PY_SRVSVC_H
+
+#include "python/py_common.h"
+
+#endif /* _PY_SRVSVC_H */
diff --git a/source4/python/py_srvsvc_conv.c b/source4/python/py_srvsvc_conv.c
new file mode 100644
index 0000000000..de43f070ed
--- /dev/null
+++ b/source4/python/py_srvsvc_conv.c
@@ -0,0 +1,43 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2003
+
+ 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 "python/py_srvsvc.h"
+#include "python/py_conv.h"
+
+static struct pyconv py_SRV_INFO_101[] = {
+ { "platform_id", PY_UINT32, offsetof(SRV_INFO_101, platform_id) },
+ { "major_version", PY_UINT32, offsetof(SRV_INFO_101, ver_major) },
+ { "minor_version", PY_UINT32, offsetof(SRV_INFO_101, ver_minor) },
+ { "server_type", PY_UINT32, offsetof(SRV_INFO_101, srv_type) },
+ { "name", PY_UNISTR2, offsetof(SRV_INFO_101, uni_name) },
+ { "comment", PY_UNISTR2, offsetof(SRV_INFO_101, uni_comment) },
+ { NULL }
+};
+
+BOOL py_from_SRV_INFO_101(PyObject **dict, SRV_INFO_101 *info)
+{
+ PyObject *obj;
+
+ *dict = from_struct(info, py_SRV_INFO_101);
+
+ PyDict_SetItemString(*dict, "level", PyInt_FromLong(101));
+
+ return True;
+}
diff --git a/source4/python/py_tdb.c b/source4/python/py_tdb.c
new file mode 100644
index 0000000000..4969c1047e
--- /dev/null
+++ b/source4/python/py_tdb.c
@@ -0,0 +1,614 @@
+/*
+ Python wrappers for TDB module
+
+ Copyright (C) Tim Potter, 2002
+
+ 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.
+*/
+
+/*
+ NOTE: Since tdb is licenced under the GPL any program that uses these bindings
+ must be distributed under the GPL license terms since this is what
+ the GPL requires.
+
+ http://www.gnu.org/licenses/gpl-faq.html#IfInterpreterIsGPL
+*/
+
+#include "includes.h"
+#include "Python.h"
+
+/* Tdb exception */
+
+PyObject *py_tdb_error;
+
+/* tdb handle object */
+
+typedef struct {
+ PyObject_HEAD
+ TDB_CONTEXT *tdb;
+} tdb_hnd_object;
+
+PyTypeObject tdb_hnd_type;
+
+PyObject *new_tdb_hnd_object(TDB_CONTEXT *tdb)
+{
+ tdb_hnd_object *obj;
+
+ obj = PyObject_New(tdb_hnd_object, &tdb_hnd_type);
+ obj->tdb = tdb;
+
+ return (PyObject *)obj;
+}
+
+PyObject *py_tdb_close(PyObject *self, PyObject *args)
+{
+ tdb_hnd_object *obj;
+
+ if (!PyArg_ParseTuple(args, "O!", &tdb_hnd_type, &obj))
+ return NULL;
+
+ if (tdb_close(obj->tdb) == -1) {
+ obj->tdb = NULL;
+ PyErr_SetString(py_tdb_error, strerror(errno));
+ return NULL;
+ }
+
+ obj->tdb = NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject *py_tdb_open(PyObject *self, PyObject *args, PyObject *kw)
+{
+ static char *kwlist[] = { "name", "hash_size", "tdb_flags",
+ "open_flags", "mode", NULL };
+ char *name;
+ int hash_size = 0, flags = TDB_DEFAULT, open_flags = -1, open_mode = 0600;
+ TDB_CONTEXT *tdb;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "s|iiii", kwlist, &name, &hash_size, &flags,
+ &open_flags, &open_mode))
+ return NULL;
+
+ /* Default open_flags to read/write */
+
+ if (open_flags == -1) {
+ if (access(name, W_OK) == -1)
+ open_flags = O_RDONLY;
+ else
+ open_flags = O_RDWR;
+ }
+
+ if (!(tdb = tdb_open(name, hash_size, flags, open_flags, open_mode))) {
+ PyErr_SetString(py_tdb_error, strerror(errno));
+ return NULL;
+ }
+
+ return new_tdb_hnd_object(tdb);
+}
+
+/*
+ * Allow a tdb to act as a python mapping (dictionary)
+ */
+
+static int tdb_traverse_count(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value,
+ void *state)
+{
+ /* Do nothing - tdb_traverse will return the number of records
+ traversed. */
+
+ return 0;
+}
+
+static int tdb_hnd_length(tdb_hnd_object *obj)
+{
+ int result;
+
+ result = tdb_traverse(obj->tdb, tdb_traverse_count, NULL);
+
+ return result;
+}
+
+static PyObject *tdb_hnd_subscript(tdb_hnd_object *obj, PyObject *key)
+{
+ TDB_DATA drec, krec;
+ PyObject *result;
+
+ if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize))
+ return NULL;
+
+ drec = tdb_fetch(obj->tdb, krec);
+
+ if (!drec.dptr) {
+ PyErr_SetString(PyExc_KeyError,
+ PyString_AsString(key));
+ return NULL;
+ }
+
+ result = PyString_FromStringAndSize(drec.dptr, drec.dsize);
+ free(drec.dptr);
+
+ return result;
+}
+
+static int tdb_ass_subscript(tdb_hnd_object *obj, PyObject *key, PyObject *value)
+{
+ TDB_DATA krec, drec;
+
+ if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize)) {
+ PyErr_SetString(PyExc_TypeError,
+ "tdb mappings have string indices only");
+ return -1;
+ }
+
+ if (!obj->tdb) {
+ PyErr_SetString(
+ py_tdb_error, "tdb object has been closed");
+ return -1;
+ }
+
+ if (!value) {
+
+ /* Delete value */
+
+ if (tdb_delete(obj->tdb, krec) == -1) {
+ PyErr_SetString(PyExc_KeyError,
+ PyString_AsString(value));
+ return -1;
+ }
+
+ } else {
+
+ /* Set value */
+
+ if (!PyArg_Parse(value, "s#", &drec.dptr, &drec.dsize)) {
+ PyErr_SetString(PyExc_TypeError,
+ "tdb mappings have string elements only");
+ return -1;
+ }
+
+ errno = 0;
+
+ if (tdb_store(obj->tdb, krec, drec, 0) < 0 ) {
+ if (errno != 0)
+ PyErr_SetFromErrno(py_tdb_error);
+ else
+ PyErr_SetString(
+ py_tdb_error,
+ (char *)tdb_errorstr(obj->tdb));
+
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static PyMappingMethods tdb_mapping = {
+ (inquiry) tdb_hnd_length,
+ (binaryfunc) tdb_hnd_subscript,
+ (objobjargproc) tdb_ass_subscript
+};
+
+/*
+ * Utility methods
+ */
+
+/* Return non-zero if a given key exists in the tdb */
+
+PyObject *py_tdb_hnd_has_key(PyObject *self, PyObject *args)
+{
+ tdb_hnd_object *obj = (tdb_hnd_object *)self;
+ TDB_DATA key;
+
+ if (!PyArg_ParseTuple(args, "s#", &key.dptr, &key.dsize))
+ return NULL;
+
+ if (!obj->tdb) {
+ PyErr_SetString(
+ py_tdb_error, "tdb object has been closed");
+ return NULL;
+ }
+
+ return PyInt_FromLong(tdb_exists(obj->tdb, key));
+}
+
+/* Return a list of keys in the tdb */
+
+static int tdb_traverse_keys(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value,
+ void *state)
+{
+ PyObject *key_list = (PyObject *)state;
+
+ PyList_Append(key_list,
+ PyString_FromStringAndSize(key.dptr, key.dsize));
+
+ return 0;
+}
+
+PyObject *py_tdb_hnd_keys(PyObject *self, PyObject *args)
+{
+ tdb_hnd_object *obj = (tdb_hnd_object *)self;
+ PyObject *key_list = PyList_New(0);
+
+ if (!obj->tdb) {
+ PyErr_SetString(py_tdb_error, "tdb object has been closed");
+ return NULL;
+ }
+
+ if (tdb_traverse(obj->tdb, tdb_traverse_keys, key_list) == -1) {
+ PyErr_SetString(py_tdb_error, "error traversing tdb");
+ Py_DECREF(key_list);
+ return NULL;
+ }
+
+ return key_list;
+}
+
+PyObject *py_tdb_hnd_first_key(PyObject *self, PyObject *args)
+{
+ tdb_hnd_object *obj = (tdb_hnd_object *)self;
+ TDB_DATA key;
+
+ if (!obj->tdb) {
+ PyErr_SetString(py_tdb_error, "tdb object has been closed");
+ return NULL;
+ }
+
+ key = tdb_firstkey(obj->tdb);
+
+ return Py_BuildValue("s#", key.dptr, key.dsize);
+}
+
+PyObject *py_tdb_hnd_next_key(PyObject *self, PyObject *py_oldkey)
+{
+ tdb_hnd_object *obj = (tdb_hnd_object *)self;
+ TDB_DATA key, oldkey;
+
+ if (!obj->tdb) {
+ PyErr_SetString(py_tdb_error, "tdb object has been closed");
+ return NULL;
+ }
+
+ if (!PyArg_Parse(py_oldkey, "s#", &oldkey.dptr, &oldkey.dsize))
+ return NULL;
+
+ key = tdb_nextkey(obj->tdb, oldkey);
+
+ return Py_BuildValue("s#", key.dptr, key.dsize);
+}
+
+/*
+ * Locking routines
+ */
+
+PyObject *py_tdb_hnd_lock_all(PyObject *self, PyObject *args)
+{
+ tdb_hnd_object *obj = (tdb_hnd_object *)self;
+ int result;
+
+ if (!obj->tdb) {
+ PyErr_SetString(py_tdb_error, "tdb object has been closed");
+ return NULL;
+ }
+
+ result = tdb_lockall(obj->tdb);
+
+ return PyInt_FromLong(result != -1);
+}
+
+PyObject *py_tdb_hnd_unlock_all(PyObject *self, PyObject *args)
+{
+ tdb_hnd_object *obj = (tdb_hnd_object *)self;
+
+ if (!obj->tdb) {
+ PyErr_SetString(py_tdb_error, "tdb object has been closed");
+ return NULL;
+ }
+
+ tdb_unlockall(obj->tdb);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Return an array of keys from a python object which must be a string or a
+ list of strings. */
+
+static BOOL make_lock_list(PyObject *py_keys, TDB_DATA **keys, int *num_keys)
+{
+ /* Are we a list or a string? */
+
+ if (!PyList_Check(py_keys) && !PyString_Check(py_keys)) {
+ PyErr_SetString(PyExc_TypeError, "arg must be list of string");
+ return False;
+ }
+
+ if (PyList_Check(py_keys)) {
+ int i;
+
+ /* Turn python list into array of keys */
+
+ *num_keys = PyList_Size(py_keys);
+ *keys = (TDB_DATA *)malloc(sizeof(TDB_DATA) * (*num_keys));
+
+ for (i = 0; i < *num_keys; i++) {
+ PyObject *key = PyList_GetItem(py_keys, i);
+
+ if (!PyString_Check(key)) {
+ PyErr_SetString(
+ PyExc_TypeError,
+ "list elements must be strings");
+ return False;
+ }
+
+ PyArg_Parse(key, "s#", &(*keys)[i].dptr,
+ &(*keys)[i].dsize);
+ }
+
+ } else {
+
+ /* Turn python string into a single key */
+
+ *keys = (TDB_DATA *)malloc(sizeof(TDB_DATA));
+ *num_keys = 1;
+ PyArg_Parse(py_keys, "s#", &(*keys)->dptr, &(*keys)->dsize);
+ }
+
+ return True;
+}
+
+PyObject *py_tdb_hnd_lock(PyObject *self, PyObject *args)
+{
+ tdb_hnd_object *obj = (tdb_hnd_object *)self;
+ PyObject *py_keys;
+ TDB_DATA *keys;
+ int num_keys, result;
+
+ if (!obj->tdb) {
+ PyErr_SetString(py_tdb_error, "tdb object has been closed");
+ return NULL;
+ }
+
+ if (!PyArg_ParseTuple(args, "O", &py_keys))
+ return NULL;
+
+ if (!make_lock_list(py_keys, &keys, &num_keys))
+ return NULL;
+
+ result = tdb_lockkeys(obj->tdb, num_keys, keys);
+
+ free(keys);
+
+ return PyInt_FromLong(result != -1);
+}
+
+PyObject *py_tdb_hnd_unlock(PyObject *self, PyObject *args)
+{
+ tdb_hnd_object *obj = (tdb_hnd_object *)self;
+
+ if (!obj->tdb) {
+ PyErr_SetString(py_tdb_error, "tdb object has been closed");
+ return NULL;
+ }
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ tdb_unlockkeys(obj->tdb);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/*
+ * tdb traversal
+ */
+
+struct traverse_info {
+ PyObject *callback;
+ PyObject *state;
+};
+
+static int tdb_traverse_traverse(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value,
+ void *state)
+{
+ struct traverse_info *info = state;
+ PyObject *arglist, *py_result;
+ int result;
+
+ arglist = Py_BuildValue("(s#s#O)", key.dptr, key.dsize, value.dptr,
+ value.dsize, info->state);
+
+ py_result = PyEval_CallObject(info->callback, arglist);
+
+ Py_DECREF(arglist);
+
+ if (!PyInt_Check(py_result)) {
+ result = 1; /* Hmm - non-integer object returned by callback */
+ goto done;
+ }
+
+ result = PyInt_AsLong(py_result);
+
+done:
+ Py_DECREF(py_result);
+ return result;
+}
+
+PyObject *py_tdb_hnd_traverse(PyObject *self, PyObject *args, PyObject *kw)
+{
+ tdb_hnd_object *obj = (tdb_hnd_object *)self;
+ static char *kwlist[] = { "traverse_fn", "state", NULL };
+ PyObject *state = Py_None, *callback;
+ struct traverse_info info;
+ int result;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "O|O", kwlist, &callback, &state))
+ return NULL;
+
+ if (!PyCallable_Check(callback)) {
+ PyErr_SetString(PyExc_TypeError, "parameter must be callable");
+ return NULL;
+ }
+
+ Py_INCREF(callback);
+ Py_INCREF(state);
+
+ info.callback = callback;
+ info.state = state;
+
+ result = tdb_traverse(obj->tdb, tdb_traverse_traverse, &info);
+
+ Py_DECREF(callback);
+ Py_DECREF(state);
+
+ return PyInt_FromLong(result);
+}
+
+/*
+ * Method dispatch table for this module
+ */
+
+static PyMethodDef tdb_methods[] = {
+ { "open", (PyCFunction)py_tdb_open, METH_VARARGS | METH_KEYWORDS },
+ { "close", (PyCFunction)py_tdb_close, METH_VARARGS },
+ { NULL }
+};
+
+/*
+ * Methods on a tdb object
+ */
+
+static PyMethodDef tdb_hnd_methods[] = {
+ { "keys", (PyCFunction)py_tdb_hnd_keys, METH_VARARGS },
+ { "has_key", (PyCFunction)py_tdb_hnd_has_key, METH_VARARGS },
+ { "first_key", (PyCFunction)py_tdb_hnd_first_key, METH_VARARGS },
+ { "next_key", (PyCFunction)py_tdb_hnd_next_key, METH_VARARGS },
+ { "lock_all", (PyCFunction)py_tdb_hnd_lock_all, METH_VARARGS },
+ { "unlock_all", (PyCFunction)py_tdb_hnd_unlock_all, METH_VARARGS },
+ { "lock", (PyCFunction)py_tdb_hnd_lock, METH_VARARGS },
+ { "unlock", (PyCFunction)py_tdb_hnd_unlock, METH_VARARGS },
+ { "traverse", (PyCFunction)py_tdb_hnd_traverse, METH_VARARGS | METH_KEYWORDS },
+ { NULL }
+};
+
+/* Deallocate a tdb handle object */
+
+static void tdb_hnd_dealloc(PyObject* self)
+{
+ tdb_hnd_object *hnd = (tdb_hnd_object *)self;
+
+ if (hnd->tdb) {
+ tdb_close(hnd->tdb);
+ hnd->tdb = NULL;
+ }
+}
+
+/* Return tdb handle attributes */
+
+static PyObject *tdb_hnd_getattr(PyObject *self, char *attrname)
+{
+ return Py_FindMethod(tdb_hnd_methods, self, attrname);
+}
+
+static char tdb_hnd_type_doc[] =
+"Python wrapper for tdb.";
+
+PyTypeObject tdb_hnd_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "tdb",
+ sizeof(tdb_hnd_object),
+ 0,
+ tdb_hnd_dealloc, /* tp_dealloc*/
+ 0, /* tp_print*/
+ tdb_hnd_getattr, /* tp_getattr*/
+ 0, /* tp_setattr*/
+ 0, /* tp_compare*/
+ 0, /* tp_repr*/
+ 0, /* tp_as_number*/
+ 0, /* tp_as_sequence*/
+ &tdb_mapping, /* tp_as_mapping*/
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ tdb_hnd_type_doc, /* tp_doc */
+};
+
+/* Constants */
+
+static struct const_vals {
+ char *name;
+ uint32 value;
+} module_const_vals[] = {
+
+ /* Flags for tdb_open() */
+
+ { "TDB_DEFAULT", TDB_DEFAULT },
+ { "TDB_CLEAR_IF_FIRST", TDB_CLEAR_IF_FIRST },
+ { "TDB_INTERNAL", TDB_INTERNAL },
+ { "TDB_NOLOCK", TDB_NOLOCK },
+ { "TDB_NOMMAP", TDB_NOMMAP },
+ { "TDB_CONVERT", TDB_CONVERT },
+ { "TDB_BIGENDIAN", TDB_BIGENDIAN },
+
+ { NULL },
+};
+
+static void const_init(PyObject *dict)
+{
+ struct const_vals *tmp;
+ PyObject *obj;
+
+ for (tmp = module_const_vals; tmp->name; tmp++) {
+ obj = PyInt_FromLong(tmp->value);
+ PyDict_SetItemString(dict, tmp->name, obj);
+ Py_DECREF(obj);
+ }
+}
+
+/* Module initialisation */
+
+void inittdb(void)
+{
+ PyObject *module, *dict;
+
+ /* Initialise module */
+
+ module = Py_InitModule("tdb", tdb_methods);
+ dict = PyModule_GetDict(module);
+
+ py_tdb_error = PyErr_NewException("tdb.error", NULL, NULL);
+ PyDict_SetItemString(dict, "error", py_tdb_error);
+
+ /* Initialise policy handle object */
+
+ tdb_hnd_type.ob_type = &PyType_Type;
+
+ PyDict_SetItemString(dict, "tdb.hnd",
+ (PyObject *)&tdb_hnd_type);
+
+ /* Initialise constants */
+
+ const_init(dict);
+}
diff --git a/source4/python/py_tdb.h b/source4/python/py_tdb.h
new file mode 100644
index 0000000000..69f251c8c1
--- /dev/null
+++ b/source4/python/py_tdb.h
@@ -0,0 +1,26 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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.
+*/
+
+#ifndef _PY_TDB_H
+#define _PY_TDB_H
+
+#include "python/py_common.h"
+
+#endif /* _PY_TDB_H */
diff --git a/source4/python/py_tdbpack.c b/source4/python/py_tdbpack.c
new file mode 100644
index 0000000000..f0718b717e
--- /dev/null
+++ b/source4/python/py_tdbpack.c
@@ -0,0 +1,725 @@
+/* -*- c-file-style: "python"; indent-tabs-mode: nil; -*-
+
+ Python wrapper for Samba tdb pack/unpack functions
+ Copyright (C) Martin Pool 2002, 2003
+
+
+ NOTE PYTHON STYLE GUIDE
+ http://www.python.org/peps/pep-0007.html
+
+
+ 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 "Python.h"
+
+/* This symbol is used in both config.h and Python.h which causes an
+ annoying compiler warning. */
+
+#ifdef HAVE_FSTAT
+#undef HAVE_FSTAT
+#endif
+
+/* This module is supposed to be standalone, however for portability
+ it would be good to use the FUNCTION_MACRO preprocessor define. */
+
+#include "include/config.h"
+
+#ifdef HAVE_FUNCTION_MACRO
+#define FUNCTION_MACRO (__FUNCTION__)
+#else
+#define FUNCTION_MACRO (__FILE__)
+#endif
+
+static PyObject * pytdbpack_number(char ch, PyObject *val_iter, PyObject *packed_list);
+static PyObject * pytdbpack_str(char ch,
+ PyObject *val_iter, PyObject *packed_list,
+ const char *encoding);
+static PyObject * pytdbpack_buffer(PyObject *val_iter, PyObject *packed_list);
+
+static PyObject *pytdbunpack_item(char, char **pbuf, int *plen, PyObject *);
+
+static PyObject *pytdbpack_data(const char *format_str,
+ PyObject *val_seq,
+ PyObject *val_list);
+
+static PyObject *
+pytdbunpack_string(char **pbuf, int *plen, const char *encoding);
+
+static void pack_le_uint32(unsigned long val_long, unsigned char *pbuf);
+
+
+static PyObject *pytdbpack_bad_type(char ch,
+ const char *expected,
+ PyObject *val_obj);
+
+static const char * pytdbpack_docstring =
+"Convert between Python values and Samba binary encodings.
+
+This module is conceptually similar to the standard 'struct' module, but it
+uses both a different binary format and a different description string.
+
+Samba's encoding is based on that used inside DCE-RPC and SMB: a
+little-endian, unpadded, non-self-describing binary format. It is intended
+that these functions be as similar as possible to the routines in Samba's
+tdb/tdbutil module, with appropriate adjustments for Python datatypes.
+
+Python strings are used to specify the format of data to be packed or
+unpacked.
+
+String encodings are implied by the database format: they may be either DOS
+codepage (currently hardcoded to 850), or Unix codepage (currently hardcoded
+to be the same as the default Python encoding).
+
+tdbpack format strings:
+
+ 'f': NUL-terminated string in codepage iso8859-1
+
+ 'P': same as 'f'
+
+ 'F': NUL-terminated string in iso-8859-1
+
+ 'd': 4 byte little-endian unsigned number
+
+ 'w': 2 byte little-endian unsigned number
+
+ 'P': \"Pointer\" value -- in the subset of DCERPC used by Samba, this is
+ really just an \"exists\" or \"does not exist\" flag. The boolean
+ value of the Python object is used.
+
+ 'B': 4-byte LE length, followed by that many bytes of binary data.
+ Corresponds to a Python integer giving the length, followed by a byte
+ string of the appropriate length.
+
+ '$': Special flag indicating that the preceding format code should be
+ repeated while data remains. This is only supported for unpacking.
+
+ Every code corresponds to a single Python object, except 'B' which
+ corresponds to two values (length and contents), and '$', which produces
+ however many make sense.
+";
+
+
+static char const pytdbpack_doc[] =
+"pack(format, values) -> buffer
+Pack Python objects into Samba binary format according to format string.
+
+arguments:
+ format -- string of tdbpack format characters
+ values -- sequence of value objects corresponding 1:1 to format characters
+
+returns:
+ buffer -- string containing packed data
+
+raises:
+ IndexError -- if there are too few values for the format
+ ValueError -- if any of the format characters is illegal
+ TypeError -- if the format is not a string, or values is not a sequence,
+ or any of the values is of the wrong type for the corresponding
+ format character
+
+notes:
+ For historical reasons, it is not an error to pass more values than are consumed
+ by the format.
+";
+
+
+static char const pytdbunpack_doc[] =
+"unpack(format, buffer) -> (values, rest)
+Unpack Samba binary data according to format string.
+
+arguments:
+ format -- string of tdbpack characters
+ buffer -- string of packed binary data
+
+returns:
+ 2-tuple of:
+ values -- sequence of values corresponding 1:1 to format characters
+ rest -- string containing data that was not decoded, or '' if the
+ whole string was consumed
+
+raises:
+ IndexError -- if there is insufficient data in the buffer for the
+ format (or if the data is corrupt and contains a variable-length
+ field extending past the end)
+ ValueError -- if any of the format characters is illegal
+
+notes:
+ Because unconsumed data is returned, you can feed it back in to the
+ unpacker to extract further fields. Alternatively, if you wish to modify
+ some fields near the start of the data, you may be able to save time by
+ only unpacking and repacking the necessary part.
+";
+
+
+const char *pytdb_dos_encoding = "cp850";
+
+/* NULL, meaning that the Samba default encoding *must* be the same as the
+ Python default encoding. */
+const char *pytdb_unix_encoding = NULL;
+
+
+/*
+ * Pack objects to bytes.
+ *
+ * All objects are first individually encoded onto a list, and then the list
+ * of strings is concatenated. This is faster than concatenating strings,
+ * and reasonably simple to code.
+ */
+static PyObject *
+pytdbpack(PyObject *self,
+ PyObject *args)
+{
+ char *format_str;
+ PyObject *val_seq, *val_iter = NULL,
+ *packed_list = NULL, *packed_str = NULL,
+ *empty_str = NULL;
+
+ /* TODO: Test passing wrong types or too many arguments */
+ if (!PyArg_ParseTuple(args, "sO", &format_str, &val_seq))
+ return NULL;
+
+ if (!(val_iter = PyObject_GetIter(val_seq)))
+ goto out;
+
+ /* Create list to hold strings until we're done, then join them all. */
+ if (!(packed_list = PyList_New(0)))
+ goto out;
+
+ if (!pytdbpack_data(format_str, val_iter, packed_list))
+ goto out;
+
+ /* this function is not officially documented but it works */
+ if (!(empty_str = PyString_InternFromString("")))
+ goto out;
+
+ packed_str = _PyString_Join(empty_str, packed_list);
+
+ out:
+ Py_XDECREF(empty_str);
+ Py_XDECREF(val_iter);
+ Py_XDECREF(packed_list);
+
+ return packed_str;
+}
+
+
+/*
+ Pack data according to FORMAT_STR from the elements of VAL_SEQ into
+ PACKED_BUF.
+
+ The string has already been checked out, so we know that VAL_SEQ is large
+ enough to hold the packed data, and that there are enough value items.
+ (However, their types may not have been thoroughly checked yet.)
+
+ In addition, val_seq is a Python Fast sequence.
+
+ Returns NULL for error (with exception set), or None.
+*/
+PyObject *
+pytdbpack_data(const char *format_str,
+ PyObject *val_iter,
+ PyObject *packed_list)
+{
+ int format_i, val_i = 0;
+
+ for (format_i = 0, val_i = 0; format_str[format_i]; format_i++) {
+ char ch = format_str[format_i];
+
+ switch (ch) {
+ /* dispatch to the appropriate packer for this type,
+ which should pull things off the iterator, and
+ append them to the packed_list */
+ case 'w':
+ case 'd':
+ case 'p':
+ if (!(packed_list = pytdbpack_number(ch, val_iter, packed_list)))
+ return NULL;
+ break;
+
+ case 'f':
+ case 'P':
+ if (!(packed_list = pytdbpack_str(ch, val_iter, packed_list, pytdb_unix_encoding)))
+ return NULL;
+ break;
+
+ case 'B':
+ if (!(packed_list = pytdbpack_buffer(val_iter, packed_list)))
+ return NULL;
+ break;
+
+ default:
+ PyErr_Format(PyExc_ValueError,
+ "%s: format character '%c' is not supported",
+ FUNCTION_MACRO, ch);
+ return NULL;
+ }
+ }
+
+ return packed_list;
+}
+
+
+static PyObject *
+pytdbpack_number(char ch, PyObject *val_iter, PyObject *packed_list)
+{
+ unsigned long val_long;
+ PyObject *val_obj = NULL, *long_obj = NULL, *result_obj = NULL;
+ PyObject *new_list = NULL;
+ unsigned char pack_buf[4];
+
+ if (!(val_obj = PyIter_Next(val_iter)))
+ goto out;
+
+ if (!(long_obj = PyNumber_Long(val_obj))) {
+ pytdbpack_bad_type(ch, "Number", val_obj);
+ goto out;
+ }
+
+ val_long = PyLong_AsUnsignedLong(long_obj);
+ pack_le_uint32(val_long, pack_buf);
+
+ /* pack as 32-bit; if just packing a 'w' 16-bit word then only take
+ the first two bytes. */
+
+ if (!(result_obj = PyString_FromStringAndSize(pack_buf, ch == 'w' ? 2 : 4)))
+ goto out;
+
+ if (PyList_Append(packed_list, result_obj) != -1)
+ new_list = packed_list;
+
+ out:
+ Py_XDECREF(val_obj);
+ Py_XDECREF(long_obj);
+ Py_XDECREF(result_obj);
+
+ return new_list;
+}
+
+
+/*
+ * Take one string from the iterator val_iter, convert it to 8-bit, and return
+ * it.
+ *
+ * If the input is neither a string nor Unicode, an exception is raised.
+ *
+ * If the input is Unicode, then it is converted to the appropriate encoding.
+ *
+ * If the input is a String, and encoding is not null, then it is converted to
+ * Unicode using the default decoding method, and then converted to the
+ * encoding. If the encoding is NULL, then the string is written out as-is --
+ * this is used when the default Python encoding is the same as the Samba
+ * encoding.
+ *
+ * I hope this approach avoids being too fragile w.r.t. being passed either
+ * Unicode or String objects.
+ */
+static PyObject *
+pytdbpack_str(char ch,
+ PyObject *val_iter, PyObject *packed_list, const char *encoding)
+{
+ PyObject *val_obj = NULL;
+ PyObject *unicode_obj = NULL;
+ PyObject *coded_str = NULL;
+ PyObject *nul_str = NULL;
+ PyObject *new_list = NULL;
+
+ if (!(val_obj = PyIter_Next(val_iter)))
+ goto out;
+
+ if (PyUnicode_Check(val_obj)) {
+ if (!(coded_str = PyUnicode_AsEncodedString(val_obj, encoding, NULL)))
+ goto out;
+ }
+ else if (PyString_Check(val_obj) && !encoding) {
+ /* For efficiency, we assume that the Python interpreter has
+ the same default string encoding as Samba's native string
+ encoding. On the PSA, both are always 8859-1. */
+ coded_str = val_obj;
+ Py_INCREF(coded_str);
+ }
+ else if (PyString_Check(val_obj)) {
+ /* String, but needs to be converted */
+ if (!(unicode_obj = PyString_AsDecodedObject(val_obj, NULL, NULL)))
+ goto out;
+ if (!(coded_str = PyUnicode_AsEncodedString(unicode_obj, encoding, NULL)))
+ goto out;
+ }
+ else {
+ pytdbpack_bad_type(ch, "String or Unicode", val_obj);
+ goto out;
+ }
+
+ if (!nul_str)
+ /* this is constant and often-used; hold it forever */
+ if (!(nul_str = PyString_FromStringAndSize("", 1)))
+ goto out;
+
+ if ((PyList_Append(packed_list, coded_str) != -1)
+ && (PyList_Append(packed_list, nul_str) != -1))
+ new_list = packed_list;
+
+ out:
+ Py_XDECREF(val_obj);
+ Py_XDECREF(unicode_obj);
+ Py_XDECREF(coded_str);
+
+ return new_list;
+}
+
+
+/*
+ * Pack (LENGTH, BUFFER) pair onto the list.
+ *
+ * The buffer must already be a String, not Unicode, because it contains 8-bit
+ * untranslated data. In some cases it will actually be UTF_16_LE data.
+ */
+static PyObject *
+pytdbpack_buffer(PyObject *val_iter, PyObject *packed_list)
+{
+ PyObject *val_obj;
+ PyObject *new_list = NULL;
+
+ /* pull off integer and stick onto list */
+ if (!(packed_list = pytdbpack_number('d', val_iter, packed_list)))
+ return NULL;
+
+ /* this assumes that the string is the right length; the old code did
+ the same. */
+ if (!(val_obj = PyIter_Next(val_iter)))
+ return NULL;
+
+ if (!PyString_Check(val_obj)) {
+ pytdbpack_bad_type('B', "String", val_obj);
+ goto out;
+ }
+
+ if (PyList_Append(packed_list, val_obj) != -1)
+ new_list = packed_list;
+
+ out:
+ Py_XDECREF(val_obj);
+ return new_list;
+}
+
+
+static PyObject *pytdbpack_bad_type(char ch,
+ const char *expected,
+ PyObject *val_obj)
+{
+ PyObject *r = PyObject_Repr(val_obj);
+ if (!r)
+ return NULL;
+ PyErr_Format(PyExc_TypeError,
+ "tdbpack: format '%c' requires %s, not %s",
+ ch, expected, PyString_AS_STRING(r));
+ Py_DECREF(r);
+ return val_obj;
+}
+
+
+/*
+ XXX: glib and Samba have quicker macro for doing the endianness conversions,
+ but I don't know of one in plain libc, and it's probably not a big deal. I
+ realize this is kind of dumb because we'll almost always be on x86, but
+ being safe is important.
+*/
+static void pack_le_uint32(unsigned long val_long, unsigned char *pbuf)
+{
+ pbuf[0] = val_long & 0xff;
+ pbuf[1] = (val_long >> 8) & 0xff;
+ pbuf[2] = (val_long >> 16) & 0xff;
+ pbuf[3] = (val_long >> 24) & 0xff;
+}
+
+
+static void pack_bytes(long len, const char *from,
+ unsigned char **pbuf)
+{
+ memcpy(*pbuf, from, len);
+ (*pbuf) += len;
+}
+
+
+
+static PyObject *
+pytdbunpack(PyObject *self,
+ PyObject *args)
+{
+ char *format_str, *packed_str, *ppacked;
+ PyObject *val_list = NULL, *ret_tuple = NULL;
+ PyObject *rest_string = NULL;
+ int format_len, packed_len;
+ char last_format = '#'; /* invalid */
+ int i;
+
+ /* get arguments */
+ if (!PyArg_ParseTuple(args, "ss#", &format_str, &packed_str, &packed_len))
+ return NULL;
+
+ format_len = strlen(format_str);
+
+ /* Allocate list to hold results. Initially empty, and we append
+ results as we go along. */
+ val_list = PyList_New(0);
+ if (!val_list)
+ goto failed;
+ ret_tuple = PyTuple_New(2);
+ if (!ret_tuple)
+ goto failed;
+
+ /* For every object, unpack. */
+ for (ppacked = packed_str, i = 0; i < format_len && format_str[i] != '$'; i++) {
+ last_format = format_str[i];
+ /* packed_len is reduced in place */
+ if (!pytdbunpack_item(format_str[i], &ppacked, &packed_len, val_list))
+ goto failed;
+ }
+
+ /* If the last character was '$', keep going until out of space */
+ if (format_str[i] == '$') {
+ if (i == 0) {
+ PyErr_Format(PyExc_ValueError,
+ "%s: '$' may not be first character in format",
+ FUNCTION_MACRO);
+ return NULL;
+ }
+ while (packed_len > 0)
+ if (!pytdbunpack_item(last_format, &ppacked, &packed_len, val_list))
+ goto failed;
+ }
+
+ /* save leftovers for next time */
+ rest_string = PyString_FromStringAndSize(ppacked, packed_len);
+ if (!rest_string)
+ goto failed;
+
+ /* return (values, rest) tuple; give up references to them */
+ PyTuple_SET_ITEM(ret_tuple, 0, val_list);
+ val_list = NULL;
+ PyTuple_SET_ITEM(ret_tuple, 1, rest_string);
+ val_list = NULL;
+ return ret_tuple;
+
+ failed:
+ /* handle failure: deallocate anything. XDECREF forms handle NULL
+ pointers for objects that haven't been allocated yet. */
+ Py_XDECREF(val_list);
+ Py_XDECREF(ret_tuple);
+ Py_XDECREF(rest_string);
+ return NULL;
+}
+
+
+static void
+pytdbunpack_err_too_short(void)
+{
+ PyErr_Format(PyExc_IndexError,
+ "%s: data too short for unpack format", FUNCTION_MACRO);
+}
+
+
+static PyObject *
+pytdbunpack_uint32(char **pbuf, int *plen)
+{
+ unsigned long v;
+ unsigned char *b;
+
+ if (*plen < 4) {
+ pytdbunpack_err_too_short();
+ return NULL;
+ }
+
+ b = *pbuf;
+ v = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24;
+
+ (*pbuf) += 4;
+ (*plen) -= 4;
+
+ return PyLong_FromUnsignedLong(v);
+}
+
+
+static PyObject *pytdbunpack_int16(char **pbuf, int *plen)
+{
+ long v;
+ unsigned char *b;
+
+ if (*plen < 2) {
+ pytdbunpack_err_too_short();
+ return NULL;
+ }
+
+ b = *pbuf;
+ v = b[0] | b[1]<<8;
+
+ (*pbuf) += 2;
+ (*plen) -= 2;
+
+ return PyInt_FromLong(v);
+}
+
+
+static PyObject *
+pytdbunpack_string(char **pbuf, int *plen, const char *encoding)
+{
+ int len;
+ char *nul_ptr, *start;
+
+ start = *pbuf;
+
+ nul_ptr = memchr(start, '\0', *plen);
+ if (!nul_ptr) {
+ pytdbunpack_err_too_short();
+ return NULL;
+ }
+
+ len = nul_ptr - start;
+
+ *pbuf += len + 1; /* skip \0 */
+ *plen -= len + 1;
+
+ return PyString_Decode(start, len, encoding, NULL);
+}
+
+
+static PyObject *
+pytdbunpack_buffer(char **pbuf, int *plen, PyObject *val_list)
+{
+ /* first get 32-bit len */
+ long slen;
+ unsigned char *b;
+ unsigned char *start;
+ PyObject *str_obj = NULL, *len_obj = NULL;
+
+ if (*plen < 4) {
+ pytdbunpack_err_too_short();
+ return NULL;
+ }
+
+ b = *pbuf;
+ slen = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24;
+
+ if (slen < 0) { /* surely you jest */
+ PyErr_Format(PyExc_ValueError,
+ "%s: buffer seems to have negative length", FUNCTION_MACRO);
+ return NULL;
+ }
+
+ (*pbuf) += 4;
+ (*plen) -= 4;
+ start = *pbuf;
+
+ if (*plen < slen) {
+ PyErr_Format(PyExc_IndexError,
+ "%s: not enough data to unpack buffer: "
+ "need %d bytes, have %d", FUNCTION_MACRO,
+ (int) slen, *plen);
+ return NULL;
+ }
+
+ (*pbuf) += slen;
+ (*plen) -= slen;
+
+ if (!(len_obj = PyInt_FromLong(slen)))
+ goto failed;
+
+ if (PyList_Append(val_list, len_obj) == -1)
+ goto failed;
+
+ if (!(str_obj = PyString_FromStringAndSize(start, slen)))
+ goto failed;
+
+ if (PyList_Append(val_list, str_obj) == -1)
+ goto failed;
+
+ Py_DECREF(len_obj);
+ Py_DECREF(str_obj);
+
+ return val_list;
+
+ failed:
+ Py_XDECREF(len_obj); /* handles NULL */
+ Py_XDECREF(str_obj);
+ return NULL;
+}
+
+
+/* Unpack a single field from packed data, according to format character CH.
+ Remaining data is at *PBUF, of *PLEN.
+
+ *PBUF is advanced, and *PLEN reduced to reflect the amount of data that has
+ been consumed.
+
+ Returns a reference to None, or NULL for failure.
+*/
+static PyObject *pytdbunpack_item(char ch,
+ char **pbuf,
+ int *plen,
+ PyObject *val_list)
+{
+ PyObject *unpacked;
+
+ if (ch == 'w') { /* 16-bit int */
+ unpacked = pytdbunpack_int16(pbuf, plen);
+ }
+ else if (ch == 'd' || ch == 'p') { /* 32-bit int */
+ /* pointers can just come through as integers */
+ unpacked = pytdbunpack_uint32(pbuf, plen);
+ }
+ else if (ch == 'f' || ch == 'P') { /* nul-term string */
+ unpacked = pytdbunpack_string(pbuf, plen, pytdb_unix_encoding);
+ }
+ else if (ch == 'B') { /* length, buffer */
+ return pytdbunpack_buffer(pbuf, plen, val_list);
+ }
+ else {
+ PyErr_Format(PyExc_ValueError,
+ "%s: format character '%c' is not supported",
+ FUNCTION_MACRO, ch);
+
+ return NULL;
+ }
+
+ /* otherwise OK */
+ if (!unpacked)
+ return NULL;
+
+ if (PyList_Append(val_list, unpacked) == -1)
+ val_list = NULL;
+
+ /* PyList_Append takes a new reference to the inserted object.
+ Therefore, we no longer need the original reference. */
+ Py_DECREF(unpacked);
+
+ return val_list;
+}
+
+
+
+
+
+
+static PyMethodDef pytdbpack_methods[] = {
+ { "pack", pytdbpack, METH_VARARGS, (char *) pytdbpack_doc },
+ { "unpack", pytdbunpack, METH_VARARGS, (char *) pytdbunpack_doc },
+};
+
+DL_EXPORT(void)
+inittdbpack(void)
+{
+ Py_InitModule3("tdbpack", pytdbpack_methods,
+ (char *) pytdbpack_docstring);
+}
diff --git a/source4/python/py_winbind.c b/source4/python/py_winbind.c
new file mode 100644
index 0000000000..e9fc4b7dd8
--- /dev/null
+++ b/source4/python/py_winbind.c
@@ -0,0 +1,724 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Python wrapper for winbind client functions.
+
+ Copyright (C) Tim Potter 2002
+
+ 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 "py_winbind.h"
+
+/*
+ * Exceptions raised by this module
+ */
+
+PyObject *winbind_error; /* A winbind call returned WINBINDD_ERROR */
+
+/* Prototypes from common.h */
+
+NSS_STATUS winbindd_request(int req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response);
+
+/*
+ * Name <-> SID conversion
+ */
+
+/* Convert a name to a sid */
+
+static PyObject *py_name_to_sid(PyObject *self, PyObject *args)
+
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ PyObject *result;
+ char *name, *p;
+ const char *sep;
+
+ if (!PyArg_ParseTuple(args, "s", &name))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ sep = lp_winbind_separator();
+
+ if ((p = strchr(name, sep[0]))) {
+ *p = 0;
+ fstrcpy(request.data.name.dom_name, name);
+ fstrcpy(request.data.name.name, p + 1);
+ } else {
+ fstrcpy(request.data.name.dom_name, lp_workgroup());
+ fstrcpy(request.data.name.name, name);
+ }
+
+ if (winbindd_request(WINBINDD_LOOKUPNAME, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ result = PyString_FromString(response.data.sid.sid);
+
+ return result;
+}
+
+/* Convert a sid to a name */
+
+static PyObject *py_sid_to_name(PyObject *self, PyObject *args)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ PyObject *result;
+ char *sid, *name;
+
+ if (!PyArg_ParseTuple(args, "s", &sid))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.data.sid, sid);
+
+ if (winbindd_request(WINBINDD_LOOKUPSID, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ asprintf(&name, "%s%s%s", response.data.name.dom_name,
+ lp_winbind_separator(), response.data.name.name);
+
+ result = PyString_FromString(name);
+
+ free(name);
+
+ return result;
+}
+
+/*
+ * Enumerate users/groups
+ */
+
+/* Enumerate domain users */
+
+static PyObject *py_enum_domain_users(PyObject *self, PyObject *args)
+{
+ struct winbindd_response response;
+ PyObject *result;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ ZERO_STRUCT(response);
+
+ if (winbindd_request(WINBINDD_LIST_USERS, NULL, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ result = PyList_New(0);
+
+ if (response.extra_data) {
+ const char *extra_data = response.extra_data;
+ fstring name;
+
+ while (next_token(&extra_data, name, ",", sizeof(fstring)))
+ PyList_Append(result, PyString_FromString(name));
+ }
+
+ return result;
+}
+
+/* Enumerate domain groups */
+
+static PyObject *py_enum_domain_groups(PyObject *self, PyObject *args)
+{
+ struct winbindd_response response;
+ PyObject *result = NULL;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ ZERO_STRUCT(response);
+
+ if (winbindd_request(WINBINDD_LIST_GROUPS, NULL, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ result = PyList_New(0);
+
+ if (response.extra_data) {
+ const char *extra_data = response.extra_data;
+ fstring name;
+
+ while (next_token(&extra_data, name, ",", sizeof(fstring)))
+ PyList_Append(result, PyString_FromString(name));
+ }
+
+ return result;
+}
+
+/*
+ * Miscellaneous domain related
+ */
+
+/* Enumerate domain groups */
+
+static PyObject *py_enum_trust_dom(PyObject *self, PyObject *args)
+{
+ struct winbindd_response response;
+ PyObject *result = NULL;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ ZERO_STRUCT(response);
+
+ if (winbindd_request(WINBINDD_LIST_TRUSTDOM, NULL, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ result = PyList_New(0);
+
+ if (response.extra_data) {
+ const char *extra_data = response.extra_data;
+ fstring name;
+
+ while (next_token(&extra_data, name, ",", sizeof(fstring)))
+ PyList_Append(result, PyString_FromString(name));
+ }
+
+ return result;
+}
+
+/* Check machine account password */
+
+static PyObject *py_check_secret(PyObject *self, PyObject *args)
+{
+ struct winbindd_response response;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ ZERO_STRUCT(response);
+
+ if (winbindd_request(WINBINDD_CHECK_MACHACC, NULL, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ return PyInt_FromLong(response.data.num_entries);
+}
+
+/*
+ * Return a dictionary consisting of all the winbind related smb.conf
+ * parameters. This is stored in the module object.
+ */
+
+static PyObject *py_config_dict(void)
+{
+ PyObject *result;
+ uid_t ulow, uhi;
+ gid_t glow, ghi;
+
+ if (!(result = PyDict_New()))
+ return NULL;
+
+ /* Various string parameters */
+
+ PyDict_SetItemString(result, "workgroup",
+ PyString_FromString(lp_workgroup()));
+
+ PyDict_SetItemString(result, "separator",
+ PyString_FromString(lp_winbind_separator()));
+
+ PyDict_SetItemString(result, "template_homedir",
+ PyString_FromString(lp_template_homedir()));
+
+ PyDict_SetItemString(result, "template_shell",
+ PyString_FromString(lp_template_shell()));
+
+ /* Winbind uid/gid range */
+
+ if (lp_winbind_uid(&ulow, &uhi)) {
+ PyDict_SetItemString(result, "uid_low", PyInt_FromLong(ulow));
+ PyDict_SetItemString(result, "uid_high", PyInt_FromLong(uhi));
+ }
+
+ if (lp_winbind_gid(&glow, &ghi)) {
+ PyDict_SetItemString(result, "gid_low", PyInt_FromLong(glow));
+ PyDict_SetItemString(result, "gid_high", PyInt_FromLong(ghi));
+ }
+
+ return result;
+}
+
+/*
+ * ID mapping
+ */
+
+/* Convert a uid to a SID */
+
+static PyObject *py_uid_to_sid(PyObject *self, PyObject *args)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int id;
+
+ if (!PyArg_ParseTuple(args, "i", &id))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.data.uid = id;
+
+ if (winbindd_request(WINBINDD_UID_TO_SID, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ return PyString_FromString(response.data.sid.sid);
+}
+
+/* Convert a gid to a SID */
+
+static PyObject *py_gid_to_sid(PyObject *self, PyObject *args)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int id;
+
+ if (!PyArg_ParseTuple(args, "i", &id))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.data.gid = id;
+
+ if (winbindd_request(WINBINDD_GID_TO_SID, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ return PyString_FromString(response.data.sid.sid);
+}
+
+/* Convert a sid to a uid */
+
+static PyObject *py_sid_to_uid(PyObject *self, PyObject *args)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ char *sid;
+
+ if (!PyArg_ParseTuple(args, "s", &sid))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.data.sid, sid);
+
+ if (winbindd_request(WINBINDD_SID_TO_UID, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ return PyInt_FromLong(response.data.uid);
+}
+
+/* Convert a sid to a gid */
+
+static PyObject *py_sid_to_gid(PyObject *self, PyObject *args)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ char *sid;
+
+ if (!PyArg_ParseTuple(args, "s", &sid))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.data.sid, sid);
+
+ if (winbindd_request(WINBINDD_SID_TO_GID, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ return PyInt_FromLong(response.data.gid);
+}
+
+/*
+ * PAM authentication functions
+ */
+
+/* Plaintext authentication */
+
+static PyObject *py_auth_plaintext(PyObject *self, PyObject *args)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ char *username, *password;
+
+ if (!PyArg_ParseTuple(args, "ss", &username, &password))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.data.auth.user, username);
+ fstrcpy(request.data.auth.pass, password);
+
+ if (winbindd_request(WINBINDD_PAM_AUTH, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ return PyInt_FromLong(response.data.auth.nt_status);
+}
+
+/* Challenge/response authentication */
+
+static PyObject *py_auth_crap(PyObject *self, PyObject *args, PyObject *kw)
+{
+ static char *kwlist[] =
+ {"username", "password", "use_lm_hash", "use_nt_hash", NULL };
+ struct winbindd_request request;
+ struct winbindd_response response;
+ char *username, *password;
+ int use_lm_hash = 1, use_nt_hash = 1;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "ss|ii", kwlist, &username, &password,
+ &use_lm_hash, &use_nt_hash))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.data.auth_crap.user, username);
+
+ generate_random_buffer(request.data.auth_crap.chal, 8, False);
+
+ if (use_lm_hash) {
+ SMBencrypt((uchar *)password, request.data.auth_crap.chal,
+ (uchar *)request.data.auth_crap.lm_resp);
+ request.data.auth_crap.lm_resp_len = 24;
+ }
+
+ if (use_nt_hash) {
+ SMBNTencrypt((uchar *)password, request.data.auth_crap.chal,
+ (uchar *)request.data.auth_crap.nt_resp);
+ request.data.auth_crap.nt_resp_len = 24;
+ }
+
+ if (winbindd_request(WINBINDD_PAM_AUTH_CRAP, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ return PyInt_FromLong(response.data.auth.nt_status);
+}
+
+/* Get user info from name */
+
+static PyObject *py_getpwnam(PyObject *self, PyObject *args)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ char *username;
+ PyObject *result;
+
+ if (!PyArg_ParseTuple(args, "s", &username))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.data.username, username);
+
+ if (winbindd_request(WINBINDD_GETPWNAM, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ if (!py_from_winbind_passwd(&result, &response)) {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+}
+
+/* Get user info from uid */
+
+static PyObject *py_getpwuid(PyObject *self, PyObject *args)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ uid_t uid;
+ PyObject *result;
+
+ if (!PyArg_ParseTuple(args, "i", &uid))
+ return NULL;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.data.uid = uid;
+
+ if (winbindd_request(WINBINDD_GETPWUID, &request, &response)
+ != NSS_STATUS_SUCCESS) {
+ PyErr_SetString(winbind_error, "lookup failed");
+ return NULL;
+ }
+
+ if (!py_from_winbind_passwd(&result, &response)) {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+}
+
+/*
+ * Method dispatch table
+ */
+
+static PyMethodDef winbind_methods[] = {
+
+ { "getpwnam", (PyCFunction)py_getpwnam, METH_VARARGS, "getpwnam(3)" },
+ { "getpwuid", (PyCFunction)py_getpwuid, METH_VARARGS, "getpwuid(3)" },
+
+ /* Name <-> SID conversion */
+
+ { "name_to_sid", (PyCFunction)py_name_to_sid, METH_VARARGS,
+ "name_to_sid(s) -> string
+
+Return the SID for a name.
+
+Example:
+
+>>> winbind.name_to_sid('FOO/Administrator')
+'S-1-5-21-406022937-1377575209-526660263-500' " },
+
+ { "sid_to_name", (PyCFunction)py_sid_to_name, METH_VARARGS,
+ "sid_to_name(s) -> string
+
+Return the name for a SID.
+
+Example:
+
+>>> import winbind
+>>> winbind.sid_to_name('S-1-5-21-406022937-1377575209-526660263-500')
+'FOO/Administrator' " },
+
+ /* Enumerate users/groups */
+
+ { "enum_domain_users", (PyCFunction)py_enum_domain_users, METH_VARARGS,
+ "enum_domain_users() -> list of strings
+
+Return a list of domain users.
+
+Example:
+
+>>> winbind.enum_domain_users()
+['FOO/Administrator', 'FOO/anna', 'FOO/Anne Elk', 'FOO/build',
+'FOO/foo', 'FOO/foo2', 'FOO/foo3', 'FOO/Guest', 'FOO/user1',
+'FOO/whoops-ptang'] " },
+
+ { "enum_domain_groups", (PyCFunction)py_enum_domain_groups,
+ METH_VARARGS,
+ "enum_domain_groups() -> list of strings
+
+Return a list of domain groups.
+
+Example:
+
+>>> winbind.enum_domain_groups()
+['FOO/cows', 'FOO/Domain Admins', 'FOO/Domain Guests',
+'FOO/Domain Users'] " },
+
+ /* ID mapping */
+
+ { "uid_to_sid", (PyCFunction)py_uid_to_sid, METH_VARARGS,
+ "uid_to_sid(int) -> string
+
+Return the SID for a UNIX uid.
+
+Example:
+
+>>> winbind.uid_to_sid(10000)
+'S-1-5-21-406022937-1377575209-526660263-500' " },
+
+ { "gid_to_sid", (PyCFunction)py_gid_to_sid, METH_VARARGS,
+ "gid_to_sid(int) -> string
+
+Return the UNIX gid for a SID.
+
+Example:
+
+>>> winbind.gid_to_sid(10001)
+'S-1-5-21-406022937-1377575209-526660263-512' " },
+
+ { "sid_to_uid", (PyCFunction)py_sid_to_uid, METH_VARARGS,
+ "sid_to_uid(string) -> int
+
+Return the UNIX uid for a SID.
+
+Example:
+
+>>> winbind.sid_to_uid('S-1-5-21-406022937-1377575209-526660263-500')
+10000 " },
+
+ { "sid_to_gid", (PyCFunction)py_sid_to_gid, METH_VARARGS,
+ "sid_to_gid(string) -> int
+
+Return the UNIX gid corresponding to a SID.
+
+Example:
+
+>>> winbind.sid_to_gid('S-1-5-21-406022937-1377575209-526660263-512')
+10001 " },
+
+ /* Miscellaneous */
+
+ { "check_secret", (PyCFunction)py_check_secret, METH_VARARGS,
+ "check_secret() -> int
+
+Check the machine trust account password. The NT status is returned
+with zero indicating success. " },
+
+ { "enum_trust_dom", (PyCFunction)py_enum_trust_dom, METH_VARARGS,
+ "enum_trust_dom() -> list of strings
+
+Return a list of trusted domains. The domain the server is a member
+of is not included.
+
+Example:
+
+>>> winbind.enum_trust_dom()
+['NPSD-TEST2', 'SP2NDOM'] " },
+
+ /* PAM authorisation functions */
+
+ { "auth_plaintext", (PyCFunction)py_auth_plaintext, METH_VARARGS,
+ "auth_plaintext(s, s) -> int
+
+Authenticate a username and password using plaintext authentication.
+The NT status code is returned with zero indicating success." },
+
+ { "auth_crap", (PyCFunction)py_auth_crap, METH_VARARGS,
+ "auth_crap(s, s) -> int
+
+Authenticate a username and password using the challenge/response
+protocol. The NT status code is returned with zero indicating
+success." },
+
+ { NULL }
+};
+
+static struct const_vals {
+ char *name;
+ uint32 value;
+ char *docstring;
+} module_const_vals[] = {
+
+ /* Well known RIDs */
+
+ { "DOMAIN_USER_RID_ADMIN", DOMAIN_USER_RID_ADMIN,
+ "Well-known RID for Administrator user" },
+
+ { "DOMAIN_USER_RID_GUEST", DOMAIN_USER_RID_GUEST,
+ "Well-known RID for Guest user" },
+
+ { "DOMAIN_GROUP_RID_ADMINS", DOMAIN_GROUP_RID_ADMINS,
+ "Well-known RID for Domain Admins group" },
+
+ { "DOMAIN_GROUP_RID_USERS", DOMAIN_GROUP_RID_USERS,
+ "Well-known RID for Domain Users group" },
+
+ { "DOMAIN_GROUP_RID_GUESTS", DOMAIN_GROUP_RID_GUESTS,
+ "Well-known RID for Domain Guests group" },
+
+ { NULL }
+};
+
+static void const_init(PyObject *dict)
+{
+ struct const_vals *tmp;
+ PyObject *obj;
+
+ for (tmp = module_const_vals; tmp->name; tmp++) {
+ obj = PyInt_FromLong(tmp->value);
+ PyDict_SetItemString(dict, tmp->name, obj);
+ Py_DECREF(obj);
+ }
+}
+
+/*
+ * Module initialisation
+ */
+
+static char winbind_module__doc__[] =
+"A python extension to winbind client functions.";
+
+void initwinbind(void)
+{
+ PyObject *module, *dict;
+
+ /* Initialise module */
+
+ module = Py_InitModule3("winbind", winbind_methods,
+ winbind_module__doc__);
+
+ dict = PyModule_GetDict(module);
+
+ winbind_error = PyErr_NewException("winbind.error", NULL, NULL);
+ PyDict_SetItemString(dict, "error", winbind_error);
+
+ /* Do samba initialisation */
+
+ py_samba_init();
+
+ /* Initialise constants */
+
+ const_init(dict);
+
+ /* Insert configuration dictionary */
+
+ PyDict_SetItemString(dict, "config", py_config_dict());
+}
diff --git a/source4/python/py_winbind.h b/source4/python/py_winbind.h
new file mode 100644
index 0000000000..10927ea6c8
--- /dev/null
+++ b/source4/python/py_winbind.h
@@ -0,0 +1,30 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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.
+*/
+
+#ifndef _PY_WINBIND_H
+#define _PY_WINBIND_H
+
+#include "python/py_common.h"
+
+/* The following definitions are from py_winbind_conv.c */
+
+BOOL py_from_winbind_passwd(PyObject **dict, struct winbindd_response *response);
+
+#endif /* _PY_WINBIND_H */
diff --git a/source4/python/py_winbind_conv.c b/source4/python/py_winbind_conv.c
new file mode 100644
index 0000000000..6e2eab5941
--- /dev/null
+++ b/source4/python/py_winbind_conv.c
@@ -0,0 +1,41 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_common.h"
+#include "python/py_conv.h"
+
+/* Convert a struct passwd to a dictionary */
+
+static struct pyconv py_passwd[] = {
+ { "pw_name", PY_STRING, offsetof(struct winbindd_response, data.pw.pw_name) },
+ { "pw_passwd", PY_STRING, offsetof(struct winbindd_response, data.pw.pw_passwd) },
+ { "pw_uid", PY_UID, offsetof(struct winbindd_response, data.pw.pw_uid) },
+ { "pw_guid", PY_GID, offsetof(struct winbindd_response, data.pw.pw_gid) },
+ { "pw_gecos", PY_STRING, offsetof(struct winbindd_response, data.pw.pw_gecos) },
+ { "pw_dir", PY_STRING, offsetof(struct winbindd_response, data.pw.pw_dir) },
+ { "pw_shell", PY_STRING, offsetof(struct winbindd_response, data.pw.pw_shell) },
+ { NULL}
+};
+
+BOOL py_from_winbind_passwd(PyObject **dict, struct winbindd_response *response)
+{
+ *dict = from_struct(response, py_passwd);
+ return True;
+}
diff --git a/source4/python/py_winreg.c b/source4/python/py_winreg.c
new file mode 100644
index 0000000000..ce27f5c533
--- /dev/null
+++ b/source4/python/py_winreg.c
@@ -0,0 +1,82 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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 "python/py_winreg.h"
+
+static struct const_vals {
+ char *name;
+ uint32 value;
+} module_const_vals[] = {
+
+ /* Registry value types */
+
+ { "REG_NONE", REG_NONE },
+ { "REG_SZ", REG_SZ },
+ { "REG_EXPAND_SZ", REG_EXPAND_SZ },
+ { "REG_BINARY", REG_BINARY },
+ { "REG_DWORD", REG_DWORD },
+ { "REG_DWORD_LE", REG_DWORD_LE },
+ { "REG_DWORD_BE", REG_DWORD_BE },
+ { "REG_LINK", REG_LINK },
+ { "REG_MULTI_SZ", REG_MULTI_SZ },
+ { "REG_RESOURCE_LIST", REG_RESOURCE_LIST },
+ { "REG_FULL_RESOURCE_DESCRIPTOR", REG_FULL_RESOURCE_DESCRIPTOR },
+ { "REG_RESOURCE_REQUIREMENTS_LIST", REG_RESOURCE_REQUIREMENTS_LIST },
+
+ { NULL },
+};
+
+static void const_init(PyObject *dict)
+{
+ struct const_vals *tmp;
+ PyObject *obj;
+
+ for (tmp = module_const_vals; tmp->name; tmp++) {
+ obj = PyInt_FromLong(tmp->value);
+ PyDict_SetItemString(dict, tmp->name, obj);
+ Py_DECREF(obj);
+ }
+}
+
+/*
+ * Module initialisation
+ */
+
+static PyMethodDef winreg_methods[] = {
+ { NULL }
+};
+
+void initwinreg(void)
+{
+ PyObject *module, *dict;
+
+ /* Initialise module */
+
+ module = Py_InitModule("winreg", winreg_methods);
+ dict = PyModule_GetDict(module);
+
+ /* Initialise constants */
+
+ const_init(dict);
+
+ /* Do samba initialisation */
+
+ py_samba_init();
+}
diff --git a/source4/python/py_winreg.h b/source4/python/py_winreg.h
new file mode 100644
index 0000000000..e19674d218
--- /dev/null
+++ b/source4/python/py_winreg.h
@@ -0,0 +1,29 @@
+/*
+ Python wrappers for DCERPC/SMB client routines.
+
+ Copyright (C) Tim Potter, 2002
+
+ 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.
+*/
+
+#ifndef _PY_WINREG_H
+#define _PY_WINREG_H
+
+#include "includes.h"
+#include "Python.h"
+
+#include "python/py_common.h"
+
+#endif /* _PY_WINREG_H */
diff --git a/source4/python/samba/.cvsignore b/source4/python/samba/.cvsignore
new file mode 100644
index 0000000000..0d20b6487c
--- /dev/null
+++ b/source4/python/samba/.cvsignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/source4/python/samba/__init__.py b/source4/python/samba/__init__.py
new file mode 100644
index 0000000000..c818ca3e04
--- /dev/null
+++ b/source4/python/samba/__init__.py
@@ -0,0 +1,7 @@
+"""samba
+
+Various Python modules for interfacing to Samba.
+
+Try using help() to examine their documentation.
+"""
+
diff --git a/source4/python/samba/printerdata.py b/source4/python/samba/printerdata.py
new file mode 100644
index 0000000000..33251f6a00
--- /dev/null
+++ b/source4/python/samba/printerdata.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+
+#
+# A python module that maps printerdata to a dictionary. We define
+# two classes. The printerdata class maps to Get/Set/Enum/DeletePrinterData
+# and the printerdata_ex class maps to Get/Set/Enum/DeletePrinterDataEx
+#
+
+#
+# TODO:
+#
+# - Implement __delitem__
+#
+
+from samba import spoolss
+
+class printerdata:
+ def __init__(self, host, creds = {}):
+ self.hnd = spoolss.openprinter(host, creds = creds)
+
+ def keys(self):
+ return self.hnd.enumprinterdata().keys()
+
+ def __getitem__(self, key):
+ return self.hnd.getprinterdata(key)['data']
+
+ def __setitem__(self, key, value):
+ # Store as REG_BINARY for now
+ self.hnd.setprinterdata({"key": "", "value": key, "type": 3,
+ "data": value})
+
+class printerdata_ex:
+ def __init__(self, host):
+ self.host = host
+ self.top_level_keys = ["PrinterDriverData", "DsSpooler", "DsDriver",
+ "DsUser"]
+
+ def keys(self):
+ return self.top_level_keys
+
+ def has_key(self, key):
+ for k in self.top_level_keys:
+ if k == key:
+ return 1
+ return 0
+
+ class printerdata_ex_subkey:
+ def __init__(self, host, key):
+ self.hnd = spoolss.openprinter(host)
+ self.key = key
+
+ def keys(self):
+ return self.hnd.enumprinterdataex(self.key).keys()
+
+ def __getitem__(self, key):
+ return self.hnd.getprinterdataex(self.key, key)['data']
+
+ def __getitem__(self, key):
+ return self.printerdata_ex_subkey(self.host, key)
diff --git a/source4/python/setup.py b/source4/python/setup.py
new file mode 100755
index 0000000000..48487fee4d
--- /dev/null
+++ b/source4/python/setup.py
@@ -0,0 +1,198 @@
+# -*- mode: python -*-
+#
+# Unix SMB/CIFS implementation.
+# Module packaging setup for Samba python extensions
+#
+# Copyright (C) Tim Potter, 2002-2003
+# Copyright (C) Martin Pool, 2002
+#
+# 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.
+#
+
+from distutils.core import setup
+from distutils.extension import Extension
+
+import sys, string, os
+
+# The Makefile passes in environment variable $PYTHON_OBJ as being the
+# list of Samba objects. This kind of goes against the distutils.cmd
+# method of adding setup commands and will also confuse people who are
+# familiar with the python Distutils module.
+
+samba_objs = os.environ.get("PYTHON_OBJS", "")
+
+samba_cflags = os.environ.get("PYTHON_CFLAGS", "")
+
+samba_srcdir = os.environ.get("SRCDIR", "")
+
+# These variables are filled in by configure
+
+samba_libs = os.environ.get("LIBS", "")
+
+# Convert libs and objs from space separated strings to lists of strings
+# for distutils to digest. Split "-l" prefix off library list.
+
+obj_list = string.split(samba_objs)
+
+lib_list = []
+
+for lib in string.split(samba_libs):
+ lib_list.append(string.replace(lib, "-l", ""))
+
+flags_list = string.split(samba_cflags)
+
+# Invoke distutils.setup
+
+setup(
+
+ # Overview information
+
+ name = "Samba Python Extensions",
+ version = "0.1",
+ author = "Tim Potter",
+ author_email = "tpot@samba.org",
+ license = "GPL",
+
+ # Get the "samba" directory of Python source. At the moment this
+ # just contains the __init__ file that makes it work as a
+ # subpackage. This is needed even though everything else is an
+ # extension module.
+ package_dir = {"samba": os.path.join(samba_srcdir, "python", "samba")},
+ packages = ["samba"],
+
+ # Module list
+ ext_package = "samba",
+ ext_modules = [
+
+ # SPOOLSS pipe module
+
+ Extension(name = "spoolss",
+ sources = [samba_srcdir + "python/py_spoolss.c",
+ samba_srcdir + "python/py_common.c",
+ samba_srcdir + "python/py_conv.c",
+ samba_srcdir + "python/py_ntsec.c",
+ samba_srcdir + "python/py_spoolss_common.c",
+ samba_srcdir + "python/py_spoolss_forms.c",
+ samba_srcdir + "python/py_spoolss_forms_conv.c",
+ samba_srcdir + "python/py_spoolss_drivers.c",
+ samba_srcdir + "python/py_spoolss_drivers_conv.c",
+ samba_srcdir + "python/py_spoolss_printers.c",
+ samba_srcdir + "python/py_spoolss_printers_conv.c",
+ samba_srcdir + "python/py_spoolss_printerdata.c",
+ samba_srcdir + "python/py_spoolss_ports.c",
+ samba_srcdir + "python/py_spoolss_ports_conv.c",
+ samba_srcdir + "python/py_spoolss_jobs.c",
+ samba_srcdir + "python/py_spoolss_jobs_conv.c",
+ ],
+ libraries = lib_list,
+ library_dirs = ["/usr/kerberos/lib"],
+ extra_compile_args = flags_list,
+ extra_objects = obj_list),
+
+ # LSA pipe module
+
+ Extension(name = "lsa",
+ sources = [samba_srcdir + "python/py_lsa.c",
+ samba_srcdir + "python/py_common.c",
+ samba_srcdir + "python/py_ntsec.c"],
+ libraries = lib_list,
+ library_dirs = ["/usr/kerberos/lib"],
+ extra_compile_args = flags_list,
+ extra_objects = obj_list),
+
+ # SAMR pipe module
+
+ Extension(name = "samr",
+ sources = [samba_srcdir + "python/py_samr.c",
+ samba_srcdir + "python/py_samr_conv.c",
+ samba_srcdir + "python/py_common.c"],
+ libraries = lib_list,
+ library_dirs = ["/usr/kerberos/lib"],
+ extra_compile_args = flags_list,
+ extra_objects = obj_list),
+
+ # winbind client module
+
+ Extension(name = "winbind",
+ sources = [samba_srcdir + "python/py_winbind.c",
+ samba_srcdir + "python/py_winbind_conv.c",
+ samba_srcdir + "python/py_conv.c",
+ samba_srcdir + "python/py_common.c"],
+ libraries = lib_list,
+ library_dirs = ["/usr/kerberos/lib"],
+ extra_compile_args = flags_list,
+ extra_objects = obj_list),
+
+ # WINREG pipe module
+
+ Extension(name = "winreg",
+ sources = [samba_srcdir + "python/py_winreg.c",
+ samba_srcdir + "python/py_common.c"],
+ libraries = lib_list,
+ library_dirs = ["/usr/kerberos/lib"],
+ extra_compile_args = flags_list,
+ extra_objects = obj_list),
+
+ # SRVSVC pipe module
+
+ Extension(name = "srvsvc",
+ sources = [samba_srcdir + "python/py_srvsvc.c",
+ samba_srcdir + "python/py_conv.c",
+ samba_srcdir + "python/py_srvsvc_conv.c",
+ samba_srcdir + "python/py_common.c"],
+ libraries = lib_list,
+ library_dirs = ["/usr/kerberos/lib"],
+ extra_compile_args = flags_list,
+ extra_objects = obj_list),
+
+ # tdb module
+
+ Extension(name = "tdb",
+ sources = [samba_srcdir + "python/py_tdb.c"],
+ libraries = lib_list,
+ library_dirs = ["/usr/kerberos/lib"],
+ extra_compile_args = flags_list,
+ extra_objects = obj_list),
+
+ # libsmb module
+
+ Extension(name = "smb",
+ sources = [samba_srcdir + "python/py_smb.c",
+ samba_srcdir + "python/py_common.c",
+ samba_srcdir + "python/py_ntsec.c"],
+ libraries = lib_list,
+ library_dirs = ["/usr/kerberos/lib"],
+ extra_compile_args = flags_list,
+ extra_objects = obj_list),
+
+ # Moving to merge all individual extensions in to one big
+ # extension. This is to avoid the fact that each extension is 3MB
+ # in size due to the lack of proper depedency management in Samba.
+
+ Extension(name = "samba",
+ sources = [samba_srcdir + "python/py_samba.c",
+ samba_srcdir + "python/py_common.c"],
+ libraries = lib_list,
+ library_dirs = ["/usr/kerberos/lib"],
+ extra_compile_args = flags_list,
+ extra_objects = obj_list),
+
+ # tdbpack/unpack extensions. Does not actually link to any Samba
+ # code, although it implements a compatible data format.
+ Extension(name = "tdbpack",
+ sources = [os.path.join(samba_srcdir, "python", "py_tdbpack.c")],
+ extra_compile_args = ["-I."])
+ ],
+)