Beispiel #1
0
class Client:
	# interface of this class is more or less compatible
	# with org.apache.commons.net.ftp.FTPClient	
	
	# This interface does not provide additional error checking,
	# however provides warnings.
	
	def __init__(self, commandNet, dataNet):
		self.commandNet = commandNet
		self.dataNet = dataNet
		self.machine = StateMachine(commandNet)
		self.DATA_TRANSFER_CONFIRMATION_BUG = False
		self.PASV_RESPONSE_READ_BUG = False
	
	def setDataTransferConfirmationBug(self, value):
		self.DATA_TRANSFER_CONFIRMATION_BUG = value
	
	def setPasvResponseReadingBug(self, value):
		self.PASV_RESPONSE_READ_BUG = value
	
	def warn(self, message):
		print "WARN %s" % message

	def connect(self, host, port):
		if self.machine.getState() != STATE_READY:
			self.warn("Expecting STATE_READY")
		
		return self.machine.connect(host, port)
	
	def isConnected(self):
		return self.machine.getState() != STATE_READY
	
	def isLogged(self):
		return (self.machine.getState() != STATE_READY
			and self.machine.getState() != STATE_CONNECTED
			and self.machine.getState() != STATE_WAITING_PASSWORD)

	def login(self, username, password):
		if self.machine.getState() != STATE_CONNECTED:
			self.warn("Expecting STATE_CONNECTED")
	
		suc = self.machine.user(username)
		if not suc:
			return False

		# no password needed for some servers
		if self.machine.getState() == STATE_LOGGED:
			return True

		## INJECTION
		# Here WAS a bug found by simulation.
		# If the following command fails, the state machine HAD stuck in WAITING_PASSWORD.
		suc = self.machine.password(password)
		if not suc:
			self.machine.clearWaitingPasswordAfterError()

		return suc

	def listFiles(self):
		if self.machine.getState() != STATE_LOGGED:
			self.warn("Expecting STATE_LOGGED")
	
		# todo: polish according to retrieveFile
		suc = self.machine.pasv()

		if not suc:
			return None

		dataSocket = self.machine.getDataSocket()
		
		## INJECTION
		# The transaction may go well (reponse code is OK) but the
		# returned IP address and port may not be readable.
		if not self.PASV_RESPONSE_READ_BUG:
			if dataSocket is None:
				self.machine.dataConnectionClearAfterError()
				return None
		else:
			self.warn("PASV_RESPONSE_READ_BUG is active")
		
		suc = self.dataNet.connect(dataSocket.hostname, dataSocket.port)
		
		if not suc:
			self.machine.dataConnectionClearAfterError()
			return None
		
		dataReader = self.dataNet.createNetworkReader()
		self.machine.dataConnectionEstablished()
		suc = self.machine.listing()
		if suc:
			data = dataReader.readAll()
			suc2 = self.machine.transferSuccessfullyDone()
			if not suc2:
				self.machine.dataConnectionClearAfterError()
				return None

			return parseListing(data)
		else:
			self.machine.dataConnectionClearAfterError()
			return None

	def changeWorkingDirectory(self, directory):
		if self.machine.getState() != STATE_LOGGED:
			self.warn("Expecting STATE_LOGGED")
			
		return self.machine.cwd(directory)
	
	def logout(self):
		if not self.isConnected():
			self.warn("Expecting isConnected")
			return False
			
		return self.machine.quit()
	
	def deleteFile(self, filename):
		if self.machine.getState() != STATE_LOGGED:
			self.warn("Expecting STATE_LOGGED")
			
		return self.machine.dele(filename)

	def retrieveFile(self, filename):
		if self.machine.getState() != STATE_LOGGED:
			self.warn("Expecting STATE_LOGGED")
			
		suc = self.machine.pasv()
		
		if not suc:
			return None
		
		dataSocket = self.machine.getDataSocket()
		
		## INJECTION
		# The transaction may go well (reponse code is OK) but the
		# returned IP address and port may not be readable.
		if not self.PASV_RESPONSE_READ_BUG:
			if dataSocket is None:
				self.machine.dataConnectionClearAfterError()
				return None
		else:
			self.warn("PASV_RESPONSE_READ_BUG is active")
					
		suc = self.dataNet.connect(dataSocket.hostname, dataSocket.port)
		
		if not suc:
			# This branch was added because of JPF, can not reproduce now.
			self.machine.dataConnectionClearAfterError()
			return None
		
		dataReader = self.dataNet.createNetworkReader()
		self.machine.dataConnectionEstablished()
		suc = self.machine.retr(filename)
		if suc:
			data = dataReader.readAll()
			suc2 = self.machine.transferSuccessfullyDone()
			## INJECTION: the fact that transferSuccessfullyDone may fail (because it reads
			# confirmation message) was discovered by JPF. Visible after two subsequent client.retrieveFile.
			if not self.DATA_TRANSFER_CONFIRMATION_BUG:
				if not suc2:
					# transaction failed, reset the state and return null
					self.machine.dataConnectionClearAfterError()
					return None
			else:
				self.warn("DATA_TRANSFER_CONFIRMATION_BUG is active")
			return data
		else:
			self.machine.dataConnectionClearAfterError()
			return None

	def retrieveFileStream(self, filename):
		if self.machine.getState() != STATE_LOGGED:
			self.warn("Expecting STATE_LOGGED")
			
		suc = self.machine.pasv()
		
		if not suc:
			return None
		
		dataSocket = self.machine.getDataSocket()

		## INJECTION
		# The transaction may go well (reponse code is OK) but the
		# returned IP address and port may not be readable.
		if not self.PASV_RESPONSE_READ_BUG:
			if dataSocket is None:
				self.machine.dataConnectionClearAfterError()
				return None
		else:
			self.warn("PASV_RESPONSE_READ_BUG is active")
		
		self.dataNet.connect(dataSocket.hostname, dataSocket.port)
		dataReader = self.dataNet.createNetworkReader()
		self.machine.dataConnectionEstablished()
		suc = self.machine.retr(filename)
		if suc:
			result = FileStream(dataReader, self.machine)
			result.setDATA_TRANSFER_CONFIRMATION_BUG(self.DATA_TRANSFER_CONFIRMATION_BUG)
			return result;
		else:
			self.machine.dataConnectionClearAfterError()
			return None
Beispiel #2
0
	def __init__(self, commandNet, dataNet):
		self.commandNet = commandNet
		self.dataNet = dataNet
		self.machine = StateMachine(commandNet)
		self.DATA_TRANSFER_CONFIRMATION_BUG = False
		self.PASV_RESPONSE_READ_BUG = False