def _reap(self, now=False): if self.reaped: return True if now and self.proc.poll() is None: # Wait for the first process to stop executing self.proc.wait() if self.proc.poll() is not None: # Stop ___hashcat_writer_thread as soon as possible (takes a bit because of the sleep(1)) self.stop_in_thread = True # This stops the ___hashcat_writer_thread # The process stopped executing, close it's write pipes self.err_w = SingleProcess._close_helper( self.err_w)[0] # Stops err_reader_thread self.out_w = SingleProcess._close_helper( self.out_w)[0] # Stops out_reader_thread # After we closed the writing end of the pipe _all_reader_thread should stop self.err_reader_thread = SingleProcess._join_helper( self.err_reader_thread)[0] self.out_reader_thread = SingleProcess._join_helper( self.out_reader_thread)[0] # This process might take a bit to shutdown because it has a sleep(1) # Mark stop_in_thread as true ASAP in order to give the thread time to stop self.in_writer_thread = SingleProcess._join_helper( self.in_writer_thread)[0] # Convert error from list to string self.err = "".join(self.err) # Mark the second process as completely stopped self.reaped = True if self.critical and self.proc.poll() != 0: # Second process could be hashcat which sometimes returns 1 but no error if SingleProcess.command_is_hashcat( self.cmd) and self.proc.poll() != 1: Comunicator.debug_logger( "Process %s exited with status %d. Stderr:\n%s" % (self.cmd, self.proc.poll(), self.err)) self._force_cleanup() Comunicator.fatal_debug_printer( "Fatal error encountered in critical single process. See logs." ) return True return False
def _reap_snd(self, now=False): if self.snd_reaped: return True if now and self.snd_proc.poll() is None: self.snd_proc.wait() # self.snd_out, _ = self.snd_proc.get_output() if self.snd_proc.poll() is not None: # Process stopped so close the writing end of the pipes self.snd_err_w.close() self.snd_err_w = None self.snd_out_w.close() self.snd_out_w = None # Cleanup the reading pipe self.comm_r.close() self.comm_r = None # After we closed the writing end of the pipe _all_reader_thread should stop self.snd_err_reader_thread.join() self.snd_err_reader_thread = None self.snd_out_reader_thread.join() self.snd_out_reader_thread = None # Convert error from list to string self.snd_err = "".join(self.snd_err) # Mark the second process as completely stopped self.snd_reaped = True if self.critical and self.snd_proc.poll() != 0: # Second process could be hashcat which sometimes returns 1 but no error if DoubleProcess.command_is_hashcat( self.snd_cmd) and self.snd_proc.poll() != 1: Comunicator.debug_logger( "Second process %s exited with status %d. Stderr:\n%s" % (self.snd_cmd, self.snd_proc.poll(), self.snd_err)) self._force_cleanup() Comunicator.fatal_debug_printer( "Fatal error encountered in critical second process. See logs." ) return True return False
def __init__(self, fst_cmd, snd_cmd, crit=True): super(DoubleProcess, self).__init__() if len(fst_cmd) == 0 or len(snd_cmd) == 0: Comunicator.fatal_debug_printer( "One empty command in chained processes '%s' | '%s'" % (fst_cmd, snd_cmd)) self.critical = crit self.ended = False # Logging data self.command = fst_cmd + ' | ' + snd_cmd self.fst_cmd = fst_cmd self.snd_cmd = snd_cmd disp1 = fst_cmd if type(fst_cmd) is str else " ".join(fst_cmd) disp2 = snd_cmd if type(snd_cmd) is str else " ".join(snd_cmd) Comunicator.debug_logger("Executing chained commands: '%s | %s'" % (disp1, disp2)) # Output variables need to be mutable in order to modify them # from generic thread self.snd_out = [] self.snd_err = [] self.fst_err = [] self.comm_r, self.comm_w = DoubleProcess.get_pipe_wrapper() self.snd_out_r, self.snd_out_w = DoubleProcess.get_pipe_wrapper() self.fst_err_r, self.fst_err_w = DoubleProcess.get_pipe_wrapper() self.snd_err_r, self.snd_err_w = DoubleProcess.get_pipe_wrapper() self.fst_reaped = False self.snd_reaped = False # Why an entire thread just to read from pipes? # Because if a pipe is full the program writing to the pipe will # get stuck until data is read from the pipe. If we simply call # wait for the process without reading data it will get stuck. # If we call readlines before we wait we might get stuck because # the writing end of the pipe is never closed... despite the program # not running anymore. self.fst_err_reader_thread = Thread(target=self._all_reader_thread, args=(self.fst_err_r, self.fst_err)) self.snd_err_reader_thread = Thread(target=self._all_reader_thread, args=(self.snd_err_r, self.snd_err)) if DoubleProcess.command_is_hashcat(self.snd_cmd): self.snd_out_reader_thread = Thread( target=self._hashcat_out_thread, args=(self.snd_out_r, self.snd_out, self.hashcat_progress, self)) else: self.snd_out_reader_thread = Thread(target=self._all_reader_thread, args=(self.snd_out_r, self.snd_out)) if type(snd_cmd) is str: snd_cmd = snd_cmd.split(' ') try: self.snd_proc = Popen(snd_cmd, stdin=self.comm_r, stdout=self.snd_out_w, stderr=self.snd_err_w) except Exception as e: Comunicator.fatal_debug_printer( "Error while trying to run command '%s':\n%s" % (snd_cmd, e)) if type(fst_cmd) is str: fst_cmd = fst_cmd.split(' ') try: self.fst_proc = Popen(fst_cmd, stdin=DoubleProcess.get_devnull_r(), stdout=self.comm_w, stderr=self.fst_err_w) except Exception as e: Comunicator.fatal_debug_printer( "Error while trying to run command '%s':\n%s" % (fst_cmd, e)) self.fst_err_reader_thread.start() self.snd_err_reader_thread.start() self.snd_out_reader_thread.start()