diff options
author | Andrew Tridgell <tridge@samba.org> | 2003-08-13 01:53:07 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2003-08-13 01:53:07 +0000 |
commit | ef2e26c91b80556af033d3335e55f5dfa6fff31d (patch) | |
tree | faa21bfd7e7b5247250b47c7891dc1a5ebee6be9 /source4/python | |
download | samba-ef2e26c91b80556af033d3335e55f5dfa6fff31d.tar.gz samba-ef2e26c91b80556af033d3335e55f5dfa6fff31d.tar.bz2 samba-ef2e26c91b80556af033d3335e55f5dfa6fff31d.zip |
first public release of samba4 code
(This used to be commit b0510b5428b3461aeb9bbe3cc95f62fc73e2b97f)
Diffstat (limited to 'source4/python')
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."]) + ], +) |