1#!/usr/bin/python 2 3import re 4import comfychair, stf 5from samba import spoolss 6 7class PrintServerTest(comfychair.TestCase): 8 """An abstract class requiring a print server.""" 9 def setUp(self): 10 # TODO: create a test printer 11 self.server = stf.get_server(platform = "nt") 12 self.require(self.server != None, "print server required") 13 # TODO: remove hardcoded printer name 14 self.printername = "p" 15 self.uncname = "\\\\%s\\%s" % \ 16 (self.server["hostname"], self.printername) 17 18class W2kPrintServerTest(comfychair.TestCase): 19 """An abstract class requiring a print server.""" 20 def setUp(self): 21 # TODO: create a test printer 22 self.server = stf.get_server(platform = "nt5") 23 self.require(self.server != None, "print server required") 24 # TODO: remove hardcoded printer name 25 self.printername = "p" 26 self.uncname = "\\\\%s\\%s" % \ 27 (self.server["hostname"], self.printername) 28 29class CredentialTest(PrintServerTest): 30 """An class that calls a function with various sets of credentials.""" 31 def runTest(self): 32 33 bad_user_creds = {"username": "spotty", 34 "domain": "dog", 35 "password": "bone"} 36 37 cases = ((self.server["administrator"], "Admin credentials", 1), 38 (bad_user_creds, "Bad credentials", 0)) 39 40 # TODO: add unpriv user case 41 42 for creds, testname, result in cases: 43 try: 44 self.runTestArg(creds) 45 except: 46 if result: 47 import traceback 48 traceback.print_exc() 49 self.fail("rpc with creds %s failed when it " 50 "should have suceeded" % creds) 51 return 52 53 if not result: 54 self.fail("rpc with creds %s suceeded when it should " 55 "have failed" % creds) 56 57class ArgTestServer(PrintServerTest): 58 """Test a RPC that takes a UNC print server name.""" 59 def runTest(self): 60 61 # List of test cases, %s substituted for server name 62 63 cases = (("", "No server name", 0), 64 ("\\\\%s", "Valid server name", 1), 65 ("\\%s", "Invalid unc server name", 0), 66 ("\\\\%s__", "Invalid unc server name", 0)) 67 68 for unc, testname, result in cases: 69 unc = re.sub("%s", self.server["hostname"], unc) 70 try: 71 self.runTestArg(unc) 72 except: 73 if result: 74 self.fail("rpc(\"%s\") failed when it should have " 75 "suceeded" % unc) 76 return 77 78 if not result: 79 # Suceeded when we should have failed 80 self.fail("rpc(\"%s\") suceeded when it should have " 81 "failed" % unc) 82 83class ArgTestServerAndPrinter(ArgTestServer): 84 """Test a RPC that takes a UNC print server or UNC printer name.""" 85 def runTest(self): 86 87 ArgTestServer.runTest(self) 88 89 # List of test cases, %s substituted for server name, %p substituted 90 # for printer name. 91 92 cases = (("\\\\%s\\%p", "Valid server and printer name", 1), 93 ("\\\\%s\\%p__", "Valid server, invalid printer name", 0), 94 ("\\\\%s__\\%p", "Invalid server, valid printer name", 0)) 95 96 for unc, testname, result in cases: 97 unc = re.sub("%s", self.server["hostname"], unc) 98 unc = re.sub("%p", self.printername, unc) 99 try: 100 self.runTestArg(unc) 101 except: 102 if result: 103 self.fail("openprinter(\"%s\") failed when it should have " 104 "suceeded" % unc) 105 return 106 107 if not result: 108 # Suceeded when we should have failed 109 self.fail("openprinter(\"%s\") suceeded when it should have " 110 "failed" % unc) 111 112class OpenPrinterArg(ArgTestServerAndPrinter): 113 """Test the OpenPrinter RPC with combinations of valid and invalid 114 server and printer names.""" 115 def runTestArg(self, unc): 116 spoolss.openprinter(unc) 117 118class OpenPrinterCred(CredentialTest): 119 """Test opening printer with good and bad credentials.""" 120 def runTestArg(self, creds): 121 spoolss.openprinter(self.uncname, creds = creds) 122 123class ClosePrinter(PrintServerTest): 124 """Test the ClosePrinter RPC on a printer handle.""" 125 def runTest(self): 126 hnd = spoolss.openprinter(self.uncname) 127 spoolss.closeprinter(hnd) 128 129class ClosePrinterServer(PrintServerTest): 130 """Test the ClosePrinter RPC on a print server handle.""" 131 def runTest(self): 132 hnd = spoolss.openprinter("\\\\%s" % self.server["hostname"]) 133 spoolss.closeprinter(hnd) 134 135class GetPrinterInfo(PrintServerTest): 136 """Retrieve printer info at various levels.""" 137 138 # Sample printer data 139 140 sample_info = { 141 0: {'printer_errors': 0, 'unknown18': 0, 'unknown13': 0, 'unknown26': 0, 'cjobs': 0, 'unknown11': 0, 'server_name': '\\\\win2kdc1', 'total_pages': 0, 'unknown15': 586, 'unknown16': 0, 'month': 2, 'unknown20': 0, 'second': 23, 'unknown22': 983040, 'unknown25': 0, 'total_bytes': 0, 'unknown27': 0, 'year': 2003, 'build_version': 2195, 'unknown28': 0, 'global_counter': 4, 'day': 13, 'minute': 53, 'total_jobs': 0, 'unknown29': 1114112, 'name': '\\\\win2kdc1\\p', 'hour': 2, 'level': 0, 'c_setprinter': 0, 'change_id': 522454169, 'major_version': 5, 'unknown23': 15, 'day_of_week': 4, 'unknown14': 1, 'session_counter': 2, 'status': 1, 'unknown7': 1, 'unknown8': 0, 'unknown9': 0, 'milliseconds': 421, 'unknown24': 0}, 142 1: {'comment': "I'm a teapot!", 'level': 1, 'flags': 8388608, 'name': '\\\\win2kdc1\\p', 'description': '\\\\win2kdc1\\p,HP LaserJet 4,Canberra office'}, 143 2: {'comment': "I'm a teapot!", 'status': 1, 'print_processor': 'WinPrint', 'until_time': 0, 'share_name': 'p', 'start_time': 0, 'device_mode': {'icm_method': 1, 'bits_per_pel': 0, 'log_pixels': 0, 'orientation': 1, 'panning_width': 0, 'color': 2, 'pels_width': 0, 'print_quality': 600, 'driver_version': 24, 'display_flags': 0, 'y_resolution': 600, 'media_type': 0, 'display_frequency': 0, 'icm_intent': 0, 'pels_height': 0, 'reserved1': 0, 'size': 220, 'scale': 100, 'dither_type': 0, 'panning_height': 0, 'default_source': 7, 'duplex': 1, 'fields': 16131, 'spec_version': 1025, 'copies': 1, 'device_name': '\\\\win2kdc1\\p', 'paper_size': 1, 'paper_length': 0, 'private': 'private', 'collate': 0, 'paper_width': 0, 'form_name': 'Letter', 'reserved2': 0, 'tt_option': 0}, 'port_name': 'LPT1:', 'sepfile': '', 'parameters': '', 'security_descriptor': {'group_sid': 'S-1-5-21-1606980848-1677128483-854245398-513', 'sacl': None, 'dacl': {'ace_list': [{'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-32-544'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-5-32-544'}, {'flags': 0, 'type': 0, 'mask': 131080, 'trustee': 'S-1-5-21-1606980848-1677128483-854245398-1121'}, {'flags': 10, 'type': 0, 'mask': 131072, 'trustee': 'S-1-3-0'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-3-0'}, {'flags': 0, 'type': 0, 'mask': 131080, 'trustee': 'S-1-5-21-1606980848-1677128483-854245398-1124'}, {'flags': 0, 'type': 0, 'mask': 131080, 'trustee': 'S-1-1-0'}, {'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-32-550'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-5-32-550'}, {'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-32-549'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-5-32-549'}, {'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-21-1606980848-1677128483-854245398-1106'}], 'revision': 2}, 'owner_sid': 'S-1-5-32-544', 'revision': 1}, 'name': '\\\\win2kdc1\\p', 'server_name': '\\\\win2kdc1', 'level': 2, 'datatype': 'RAW', 'cjobs': 0, 'average_ppm': 0, 'priority': 1, 'driver_name': 'HP LaserJet 4', 'location': 'Canberra office', 'attributes': 8776, 'default_priority': 0}, 144 3: {'flags': 4, 'security_descriptor': {'group_sid': 'S-1-5-21-1606980848-1677128483-854245398-513', 'sacl': None, 'dacl': {'ace_list': [{'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-32-544'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-5-32-544'}, {'flags': 0, 'type': 0, 'mask': 131080, 'trustee': 'S-1-5-21-1606980848-1677128483-854245398-1121'}, {'flags': 10, 'type': 0, 'mask': 131072, 'trustee': 'S-1-3-0'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-3-0'}, {'flags': 0, 'type': 0, 'mask': 131080, 'trustee': 'S-1-5-21-1606980848-1677128483-854245398-1124'}, {'flags': 0, 'type': 0, 'mask': 131080, 'trustee': 'S-1-1-0'}, {'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-32-550'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-5-32-550'}, {'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-32-549'}, {'flags': 9, 'type': 0, 'mask': 983056, 'trustee': 'S-1-5-32-549'}, {'flags': 0, 'type': 0, 'mask': 983052, 'trustee': 'S-1-5-21-1606980848-1677128483-854245398-1106'}], 'revision': 2}, 'owner_sid': 'S-1-5-32-544', 'revision': 1}, 'level': 3} 145 } 146 147 def runTest(self): 148 self.hnd = spoolss.openprinter(self.uncname) 149 150 # Everyone should have getprinter levels 0-3 151 152 for i in (0, 1, 2, 3): 153 info = self.hnd.getprinter(level = i) 154 try: 155 stf.dict_check(self.sample_info[i], info) 156 except ValueError, msg: 157 raise "info%d: %s" % (i, msg) 158 159class EnumPrinters(PrintServerTest): 160 """Enumerate print info at various levels.""" 161 162 sample_info = { 163 164 0: {'q': {'printer_errors': 0, 'unknown18': 0, 'unknown13': 0, 'unknown26': 0, 'cjobs': 0, 'unknown11': 0, 'server_name': '', 'total_pages': 0, 'unknown15': 586, 'unknown16': 0, 'month': 2, 'unknown20': 0, 'second': 23, 'unknown22': 983040, 'unknown25': 0, 'total_bytes': 0, 'unknown27': 0, 'year': 2003, 'build_version': 2195, 'unknown28': 0, 'global_counter': 4, 'day': 13, 'minute': 53, 'total_jobs': 0, 'unknown29': -1833435136, 'name': 'q', 'hour': 2, 'level': 0, 'c_setprinter': 0, 'change_id': 522454169, 'major_version': 5, 'unknown23': 15, 'day_of_week': 4, 'unknown14': 1, 'session_counter': 1, 'status': 0, 'unknown7': 1, 'unknown8': 0, 'unknown9': 0, 'milliseconds': 421, 'unknown24': 0}, 'p': {'printer_errors': 0, 'unknown18': 0, 'unknown13': 0, 'unknown26': 0, 'cjobs': 0, 'unknown11': 0, 'server_name': '', 'total_pages': 0, 'unknown15': 586, 'unknown16': 0, 'month': 2, 'unknown20': 0, 'second': 23, 'unknown22': 983040, 'unknown25': 0, 'total_bytes': 0, 'unknown27': 0, 'year': 2003, 'build_version': 2195, 'unknown28': 0, 'global_counter': 4, 'day': 13, 'minute': 53, 'total_jobs': 0, 'unknown29': -1831337984, 'name': 'p', 'hour': 2, 'level': 0, 'c_setprinter': 0, 'change_id': 522454169, 'major_version': 5, 'unknown23': 15, 'day_of_week': 4, 'unknown14': 1, 'session_counter': 1, 'status': 1, 'unknown7': 1, 'unknown8': 0, 'unknown9': 0, 'milliseconds': 421, 'unknown24': 0}, 'magpie': {'printer_errors': 0, 'unknown18': 0, 'unknown13': 0, 'unknown26': 0, 'cjobs': 0, 'unknown11': 0, 'server_name': '', 'total_pages': 0, 'unknown15': 586, 'unknown16': 0, 'month': 2, 'unknown20': 0, 'second': 23, 'unknown22': 983040, 'unknown25': 0, 'total_bytes': 0, 'unknown27': 0, 'year': 2003, 'build_version': 2195, 'unknown28': 0, 'global_counter': 4, 'day': 13, 'minute': 53, 'total_jobs': 0, 'unknown29': 1114112, 'name': 'magpie', 'hour': 2, 'level': 0, 'c_setprinter': 0, 'change_id': 522454169, 'major_version': 5, 'unknown23': 15, 'day_of_week': 4, 'unknown14': 1, 'session_counter': 1, 'status': 0, 'unknown7': 1, 'unknown8': 0, 'unknown9': 0, 'milliseconds': 421, 'unknown24': 0}}, 165 166 1: {'q': {'comment': 'cheepy birds', 'level': 1, 'flags': 8388608, 'name': 'q', 'description': 'q,HP LaserJet 4,'}, 'p': {'comment': "I'm a teapot!", 'level': 1, 'flags': 8388608, 'name': 'p', 'description': 'p,HP LaserJet 4,Canberra office'}, 'magpie': {'comment': '', 'level': 1, 'flags': 8388608, 'name': 'magpie', 'description': 'magpie,Generic / Text Only,'}} 167 } 168 169 def runTest(self): 170 for i in (0, 1): 171 info = spoolss.enumprinters( 172 "\\\\%s" % self.server["hostname"], level = i) 173 try: 174 stf.dict_check(self.sample_info[i], info) 175 except ValueError, msg: 176 raise "info%d: %s" % (i, msg) 177 178class EnumPrintersArg(ArgTestServer): 179 def runTestArg(self, unc): 180 spoolss.enumprinters(unc) 181 182class EnumPrintersCred(CredentialTest): 183 """Test opening printer with good and bad credentials.""" 184 def runTestArg(self, creds): 185 spoolss.enumprinters( 186 "\\\\%s" % self.server["hostname"], creds = creds) 187 188class EnumPrinterdrivers(PrintServerTest): 189 190 sample_info = { 191 1: {'Okipage 10ex (PCL5E) : STANDARD': {'name': 'Okipage 10ex (PCL5E) : STANDARD', 'level': 1}, 'Generic / Text Only': {'name': 'Generic / Text Only', 'level': 1}, 'Brother HL-1030 series': {'name': 'Brother HL-1030 series', 'level': 1}, 'Brother HL-1240 series': {'name': 'Brother HL-1240 series', 'level': 1}, 'HP DeskJet 1220C Printer': {'name': 'HP DeskJet 1220C Printer', 'level': 1}, 'HP LaserJet 4100 PCL 6': {'name': 'HP LaserJet 4100 PCL 6', 'level': 1}, 'HP LaserJet 4': {'name': 'HP LaserJet 4', 'level': 1}}, 192 2: {'Okipage 10ex (PCL5E) : STANDARD': {'version': 2, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\2\\RASDDUI.DLL', 'name': 'Okipage 10ex (PCL5E) : STANDARD', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\2\\RASDD.DLL', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\2\\OKIPAGE.DLL', 'level': 2, 'architecture': 'Windows NT x86'}, 'Generic / Text Only': {'version': 3, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\UNIDRVUI.DLL', 'name': 'Generic / Text Only', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\3\\UNIDRV.DLL', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\TTY.GPD', 'level': 2, 'architecture': 'Windows NT x86'}, 'Brother HL-1030 series': {'version': 3, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\BRUHL99A.DLL', 'name': 'Brother HL-1030 series', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\3\\BROHL99A.DLL', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\BROHL103.PPD', 'level': 2, 'architecture': 'Windows NT x86'}, 'Brother HL-1240 series': {'version': 3, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\BRUHL99A.DLL', 'name': 'Brother HL-1240 series', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\3\\BROHL99A.DLL', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\BROHL124.PPD', 'level': 2, 'architecture': 'Windows NT x86'}, 'HP DeskJet 1220C Printer': {'version': 3, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\HPW8KMD.DLL', 'name': 'HP DeskJet 1220C Printer', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\3\\HPW8KMD.DLL', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\HPW8KMD.DLL', 'level': 2, 'architecture': 'Windows NT x86'}, 'HP LaserJet 4100 PCL 6': {'version': 3, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\HPBF042E.DLL', 'name': 'HP LaserJet 4100 PCL 6', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\3\\HPBF042G.DLL', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\3\\HPBF042I.PMD', 'level': 2, 'architecture': 'Windows NT x86'}, 'HP LaserJet 4': {'version': 2, 'config_file': '\\\\WIN2KDC1\\print$\\W32X86\\2\\hpblff0.dll', 'name': 'HP LaserJet 4', 'driver_path': '\\\\WIN2KDC1\\print$\\W32X86\\2\\hpblff2.dll', 'data_file': '\\\\WIN2KDC1\\print$\\W32X86\\2\\hpblff39.pmd', 'level': 2, 'architecture': 'Windows NT x86'}} 193 } 194 195 def runTest(self): 196 for i in (1, 2): 197 info = spoolss.enumprinterdrivers( 198 "\\\\%s" % self.server["hostname"], level = i) 199 try: 200 if not self.sample_info.has_key(i): 201 self.log("%s" % info) 202 self.fail() 203 stf.dict_check(self.sample_info[i], info) 204 except ValueError, msg: 205 raise "info%d: %s" % (i, msg) 206 207class EnumPrinterdriversArg(ArgTestServer): 208 def runTestArg(self, unc): 209 spoolss.enumprinterdrivers(unc) 210 211class EnumPrinterdriversCred(CredentialTest): 212 """Test opening printer with good and bad credentials.""" 213 def runTestArg(self, creds): 214 spoolss.enumprinterdrivers( 215 "\\\\%s" % self.server["hostname"], creds = creds) 216 217def usage(): 218 print "Usage: spoolss.py [options] [test1[,test2...]]" 219 print "\t -v/--verbose Display debugging information" 220 print "\t -l/--list-tests List available tests" 221 print 222 print "A list of comma separated test names or regular expressions" 223 print "can be used to filter the tests performed." 224 225def test_match(subtest_list, test_name): 226 """Return true if a test matches a comma separated list of regular 227 expression of test names.""" 228 # re.match does an implicit ^ at the start of the pattern. 229 # Explicitly anchor to end to avoid matching substrings. 230 for s in string.split(subtest_list, ","): 231 if re.match(s + "$", test_name): 232 return 1 233 return 0 234 235if __name__ == "__main__": 236 import os, sys, string 237 import getopt 238 239 try: 240 opts, args = getopt.getopt(sys.argv[1:], "vl", \ 241 ["verbose", "list-tests"]) 242 except getopt.GetoptError: 243 usage() 244 sys.exit(0) 245 246 verbose = 0 247 list_tests = 0 248 249 for opt, arg in opts: 250 if opt in ("-v", "--verbose"): 251 verbose = 1 252 if opt in ("-l", "--list-tests"): 253 list_tests = 1 254 255 if len(args) > 1: 256 usage() 257 sys.exit(0) 258 259 test_list = [ 260 OpenPrinterArg, 261 OpenPrinterCred, 262 ClosePrinter, 263 ClosePrinterServer, 264 GetPrinterInfo, 265 EnumPrinters, 266 EnumPrintersCred, 267 EnumPrintersArg, 268 EnumPrinterdrivers, 269 EnumPrinterdriversCred, 270 EnumPrinterdriversArg, 271 ] 272 273 if len(args): 274 t = [] 275 for test in test_list: 276 if test_match(args[0], test.__name__): 277 t.append(test) 278 test_list = t 279 280 if os.environ.has_key("SAMBA_DEBUG"): 281 spoolss.setup_logging(interactive = 1) 282 spoolss.set_debuglevel(10) 283 284 if list_tests: 285 for test in test_list: 286 print test.__name__ 287 else: 288 comfychair.runtests(test_list, verbose = verbose) 289