From ef2e26c91b80556af033d3335e55f5dfa6fff31d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 13 Aug 2003 01:53:07 +0000 Subject: first public release of samba4 code (This used to be commit b0510b5428b3461aeb9bbe3cc95f62fc73e2b97f) --- source4/python/examples/spoolss/changeid.py | 34 ++++ source4/python/examples/spoolss/enumprinters.py | 36 ++++ source4/python/examples/spoolss/psec.py | 88 +++++++++ source4/python/examples/tdbpack/.cvsignore | 2 + source4/python/examples/tdbpack/oldtdbutil.py | 144 ++++++++++++++ source4/python/examples/tdbpack/tdbtimetrial.py | 12 ++ source4/python/examples/tdbpack/test_tdbpack.py | 253 ++++++++++++++++++++++++ 7 files changed, 569 insertions(+) create mode 100755 source4/python/examples/spoolss/changeid.py create mode 100755 source4/python/examples/spoolss/enumprinters.py create mode 100755 source4/python/examples/spoolss/psec.py create mode 100644 source4/python/examples/tdbpack/.cvsignore create mode 100644 source4/python/examples/tdbpack/oldtdbutil.py create mode 100755 source4/python/examples/tdbpack/tdbtimetrial.py create mode 100755 source4/python/examples/tdbpack/test_tdbpack.py (limited to 'source4/python/examples') 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 " + 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 [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 ' + +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() + -- cgit