def ipp(self, host, lang): try: # poor man's way to get printer info via IPP sys.stdout.write("Checking for IPP support: ") body = ( "\x01\x01\x00\x0b\x00\x01\xab\x10\x01G\x00\x12attributes-charset\x00\x05utf-8H" + "\x00\x1battributes-natural-language\x00\x02enE\x00\x0bprinter-uri\x00\x14ipp:" + "//localhost/ipp/D\x00\x14requested-attributes\x00\x13printer-description\x03" ).encode() request = urllib.request.Request( "http://" + host + ":631/", data=body, headers={'Content-type': 'application/ipp'}) response = urllib.request.urlopen( request, timeout=self.timeout).read().decode() # get name of device model = item(re.findall("MDL:(.+?);", response)) # e.g. MDL:hp LaserJet 4250 # get language support langs = item(re.findall("CMD:(.+?);", response)) # e.g. CMD:PCL,PJL,POSTSCRIPT self.support = [ _f for _f in [re.findall(re.escape(pdl), langs, re.I) for pdl in lang] if _f ] self.set_support(model) output().green("found") except Exception as e: output().errmsg("not found", e)
def do_hold(self, arg): "Enable job retention." self.chitchat("Setting job retention, reconnecting to see if still enabled") self.do_set('HOLD=ON', False) self.do_reconnect() self.logger.raw("Retention for future print jobs: ", '') hold = self.do_info('variables', '^HOLD', False) self.logger.info(item(re.findall("=(.*)\s+\[", item(item(hold)))) or 'NOT AVAILABLE')
def do_print(self, arg): 'Print image file or raw text: print <file>|"text"' ''' ┌──────────────────────────────────────────────────────────┐ │ Poor man's driverless PCL based printing (experimental) │ ├──────────────────────────────────────────────────────────┤ │ Warning: ImageMagick and Ghostscript are used to convert │ │ the document to be printed into a language understood be │ │ the printer. Don't print anything from untrusted sources │ │ as it may be a security risk (CVE-2016–3714, 2016-7976). │ └──────────────────────────────────────────────────────────┘ ''' if not arg: arg = raw_input('File or "text": ') if arg.startswith('"'): data = arg.strip('"') # raw text string elif arg.endswith('.ps'): data = file().read(arg) # postscript file else: # anything else… try: self.chitchat("Converting '" + arg + "' to PCL") pdf = ['-density', '300'] if arg.endswith('.pdf') else [] cmd = ['convert' ] + pdf + [arg, '-quality', '100', 'pcl' + ':-'] out, err = subprocess.PIPE, subprocess.PIPE p = subprocess.Popen(cmd, stdout=out, stderr=err) data, stderr = p.communicate() except: stderr = "ImageMagick or Ghostscript missing" if stderr: output().errmsg("Cannot convert", item(stderr.splitlines())) if data: self.send(c.UEL + data + c.UEL) # send pcl datastream to printer
def snmp(self, host, lang): try: sys.stdout.write("Checking for SNMP support: ") # query device description and supported languages desc, desc_oid = [], '1.3.6.1.2.1.25.3.2.1.3' # HOST-RESOURCES-MIB → hrDeviceDescr pdls, pdls_oid = [], '1.3.6.1.2.1.43.15.1.1.5.1' # Printer-MIB → prtInterpreterDescription error, error_status, idx, binds = cmdgen.CommandGenerator().nextCmd( cmdgen.CommunityData('public', mpModel=0), cmdgen.UdpTransportTarget( (host, 161), timeout=self.timeout, retries=0), desc_oid, pdls_oid) # exit on error if error: raise Exception(error) if error_status: raise Exception(error_status.prettyPrint()) # parse response for row in binds: for key, val in row: if desc_oid in str(key): desc.append(str(val)) if pdls_oid in str(key): pdls.append(str(val)) # get name of device model = item(desc) # get language support langs = ','.join(pdls) self.support = filter(None, [re.findall(re.escape(pdl), langs, re.I) for pdl in lang]) self.set_support(model) output().green("found") except NameError: output().errmsg("not found", "pysnmp module not installed") except Exception as e: output().errmsg("not found", str(e))
def cmd(self, str_send, wait=True, crop=True, binary=False): str_recv = "" # response buffer str_stat = "" # status buffer token = c.DELIMITER + str(random.randrange(2**16)) # unique delimiter status = '@PJL INFO STATUS' + c.EOL if self.status and wait else '' footer = '@PJL ECHO ' + token + c.EOL + c.EOL if wait else '' # send command to printer device try: cmd_send = c.UEL + str_send + c.EOL + status + footer + c.UEL # write to logfile #self.logger.write(os.linesep + "%%%%%%%%%%%%%%%%%%%%%%%%%% Sending Payload %%%%%%%%%%%%%%%%%%%%%%%%%%" + os.linesep) #self.logger.write("%%% Timestamp: " + time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime()) + os.linesep) #self.logger.write(os.linesep + str_send + os.linesep) #self.logger.write("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" + os.linesep + os.linesep) # sent to printer self.send(cmd_send) # for commands that expect a response if wait: # use random token as delimiter PJL responses str_recv = self.recv('(@PJL ECHO\s+)?' + token + '.*$', wait, True, binary) if self.status: # get status messages and remove them from received buffer str_stat = item(re.findall("@PJL INFO STATUS.*", str_recv, re.DOTALL)) str_recv = re.compile('\x0c?@PJL INFO STATUS.*', re.DOTALL).sub('', str_recv) if crop: # crop very first PJL line which is echoed by most interpreters str_recv = re.sub(r'^\x04?(\x00+)?@PJL.*' + c.EOL, '', str_recv) return self.pjl_err(str_recv, str_stat) # handle CTRL+C and exceptions except (KeyboardInterrupt, Exception) as e: if not self.fuzz or not str(e): self.reconnect(str(e)) return ""
def idlist(self): list = [] str_send = '*s4T' # set location type (downloaded) str_send += c.ESC + '*s0U' # set location unit (all units) str_send += c.ESC + '*s1I' # set inquire entity (macros) str_recv = self.cmd(str_send) idlist = re.findall('IDLIST="(.*),?"', str_recv) ### maybe this can for id in item(idlist).split(","): ### be packed into if id.startswith('1'): list.append(int(id)) ### a single regex return list
def http(self, host): try: # poor man's way get http title sys.stdout.write("Checking for HTTP support: ") html = urllib2.urlopen("http://" + host, timeout=self.timeout).read() # cause we are to parsimonious to import BeautifulSoup ;) title = re.findall("<title.*?>\n?(.+?)\n?</title>", html, re.I|re.M|re.S) # get name of device model = item(title) # get language support self.set_support(model) output().green("found") except Exception as e: output().errmsg("not found", str(e))
def put(self, path, data): path = self.basename(path) pclfs = self.dirlist() # re-use macro id if file name already present if path in pclfs: id = pclfs[path][0] # find free macro id not already reserved for file else: id = str(item(set(c.BLOCKRANGE).difference(self.idlist()))) # abort if we have used up the whole macro id space if not id: return self.logger.warning("Out of macro slots.") self.chitchat("Using macro id #" + id) # retrieve and update superblock size = str(len(data)) date = str(conv().now()) pclfs[path] = [id, size, date] self.update_superblock(pclfs) # save data as pcl macro on printer self.define_macro(id, data)
def showstatus(self, str_stat): codes = {}; messages = {} # get status codes for (num, code) in re.findall('CODE(\d+)?\s*=\s*(\d+)', str_stat): codes[num] = code # get status messages for (num, mstr) in re.findall('DISPLAY(\d+)?\s*=\s*"(.*)"', str_stat): messages[num] = mstr # show codes and messages for num, code in codes.items(): message = messages[num] if num in messages else "UNKNOWN STATUS" # workaround for hp printers with wrong range if code.startswith("32"): code = str(int(code) - 2000) # show status from display and codebook error = item(codebook().get_errors(code), 'Unknown status') self.logger.errmsg("CODE " + code + ": " + message, error)
def file_exists(self, path): str_recv = self.cmd('@PJL FSQUERY NAME="' + path + '"', True, False) size = re.findall("TYPE\s*=\s*FILE\s+SIZE\s*=\s*(\d*)", str_recv) # return file size return conv().int(item(size, c.NONEXISTENT))