def put(self, args): """ Implements the PUT command to push a file to the server. Args: args (list): the list of arguments passed to the command. Returns: True or False depending on the success of the operation. """ if len(args) != 1: print 'Usage: put <filename>' return filepath = args[0] filename = os.path.split(filepath) self.PTFTP_STATE = state.TFTPState(self.peer, proto.OP_WRQ, '', filepath, self.transfer_mode, not self.rfc1350) try: self.PTFTP_STATE.file = open(filepath, 'rb') self.PTFTP_STATE.filesize = os.stat(filepath)[stat.ST_SIZE] self.PTFTP_STATE.packetnum = 0 self.PTFTP_STATE.state = state.STATE_SEND except IOError, e: print 'Error:', os.strerror(e.errno) print "Can't read from local file %s!" % filepath return False
def put(self, args): """ Implements the PUT command to push a file to the server. Args: args (list): the list of arguments passed to the command. Returns: True or False depending on the success of the operation. """ if len(args) != 1: print('Usage: put <filename>') return filepath = args[0] self.PTFTP_STATE = state.TFTPState(self.peer, proto.OP_WRQ, '', filepath, self.transfer_mode, not self.rfc1350) try: self.PTFTP_STATE.file = open(filepath, 'rb') self.PTFTP_STATE.filesize = os.stat(filepath)[stat.ST_SIZE] self.PTFTP_STATE.packetnum = 0 self.PTFTP_STATE.state = state.STATE_SEND except IOError as e: print('Error: {}'.format(os.strerror(e.errno))) print('Can\'t read from local file {}!'.format(filepath)) return False opts = dict(self.opts) # When not running in RFC1350 compliance mode, append the # tsize option to the request options to specify the # transfered file size to the server. if not self.rfc1350: opts[proto.TFTP_OPTION_TSIZE] = self.PTFTP_STATE.filesize # Everything's OK, let's go print("Pushing '%s' to the remote host..." % filepath) packet = proto.TFTPHelper.createWRQ(filepath, self.transfer_mode, opts) transfer_start = datetime.today() self.sock.send(packet, self.peer) self.handle() transfer_time = datetime.today() - transfer_start if self.error: error, errmsg = self.error if error and errmsg: print('Error: {}'.format(errmsg)) return False print('Transfer complete, {} bytes ({:.2f} kB/s)'.format( self.PTFTP_STATE.filesize, self.__get_speed(self.PTFTP_STATE.filesize, transfer_time))) return True
def get(self, args): """ Implements the GET command to retrieve a file from the server. Args: args (list): the list of arguments passed to the command. Returns: True or False depending on the success of the operation. """ if len(args) < 1 or len(args) > 2: print 'Usage: get [-f] <filename>' return False filepath = args[0] overwrite = False if len(args) == 2: filepath = args[1] if args[0] == '-f': overwrite = True (_, filename) = os.path.split(filepath) # First, check we're not going to overwrite an existing file if not overwrite: try: open(filename) print "Error: local file %s already exists!" % filename print 'Use get -f to overwrite the local file.' return False except IOError: pass self.PTFTP_STATE = state.TFTPState(self.peer, proto.OP_RRQ, '', filepath, self.transfer_mode, not self.rfc1350) # Then, before sending anything to the server, open the file # for writing try: # We don't want tempfile to automatically delete the temporary # file on close() as we have to copy its content to the destination # file first. We'll handle it's deletion on our own. self.PTFTP_STATE.file = tempfile.NamedTemporaryFile(delete=False) self.PTFTP_STATE.packetnum = 1 self.PTFTP_STATE.state = state.STATE_RECV except IOError, e: print 'Error:', os.strerror(e.errno) print "Can't write to temporary file %s!" % \ self.PTFTP_STATE.file.name return False
def serveWRQ(self, op, request): """ Serves WRQ packets (PUT requests). Args: op (integer): the TFTP opcode. request (string): the TFTP packet without its opcode. Returns: A response packet (as a string) or None if the request is ignored for some reason. """ try: filename, mode, opts = proto.TFTPHelper.parseWRQ(request) except SyntaxError: # Ignore malfored WRQ requests return None peer_state = state.TFTPState(self.client_address, op, self.server.root, filename, mode, not self.server.strict_rfc1350) if not peer_state.filepath.startswith(self.server.root): peer_state.state = state.STATE_ERROR peer_state.error = proto.ERROR_ACCESS_VIOLATION l.warning('Out-of-jail path requested: %s!' % filename, extra=peer_state.extra(notify.TRANSFER_FAILED)) return self.finish_state(peer_state) try: # Try to open the file. If it succeeds, it means the file # already exists and report the error peer_state.file = open(peer_state.filepath) peer_state.state = state.STATE_ERROR peer_state.error = proto.ERROR_FILE_ALREADY_EXISTS l.warning('Client attempted to overwrite file %s!' % filename, extra=peer_state.extra(notify.TRANSFER_FAILED)) return self.finish_state(peer_state) except IOError as e: # Otherwise, if the open failed because the file did not # exist, create it and go on if e.errno == errno.ENOENT: try: peer_state.file = open(peer_state.filepath, 'wb') peer_state.packetnum = 0 peer_state.state = state.STATE_RECV_ACK l.info('Upload of %s began.' % filename, extra=peer_state.extra(notify.TRANSFER_STARTED)) except IOError: peer_state.state = state.STATE_ERROR peer_state.error = proto.ERROR_ACCESS_VIOLATION l.warning('Error creating file %s for upload!' % filename, extra=peer_state.extra(notify.TRANSFER_FAILED)) else: peer_state.state = state.STATE_ERROR peer_state.error = proto.ERROR_ACCESS_VIOLATION l.warning('Error creating file %s for upload!' % filename, extra=peer_state.extra(notify.TRANSFER_FAILED)) # Only set options if not running in RFC1350 compliance mode if not self.server.strict_rfc1350 and len(opts): opts = proto.TFTPHelper.parse_options(opts) if opts: # HOOK: this is where we should check that we accept # the options requested by the client. peer_state.packetnum = 1 peer_state.state = state.STATE_SEND_OACK peer_state.set_opts(opts) else: peer_state.state = state.STATE_ERROR peer_state.error = proto.ERROR_OPTION_NEGOCIATION return self.finish_state(peer_state)
def serveRRQ(self, op, request): """ Serves RRQ packets (GET requests). Args: op (integer): the TFTP opcode. request (string): the TFTP packet without its opcode. Returns: A response packet (as a string) or None if the request is ignored for some reason. """ try: filename, mode, opts = proto.TFTPHelper.parseRRQ(request) except SyntaxError: # Ignore malformed RRQ requests return None peer_state = state.TFTPState(self.client_address, op, self.server.root, filename, mode, not self.server.strict_rfc1350) if not peer_state.filepath.startswith(self.server.root): peer_state.state = state.STATE_ERROR peer_state.error = proto.ERROR_ACCESS_VIOLATION l.warning('Out-of-jail path requested: %s!' % filename, extra=peer_state.extra(notify.TRANSFER_FAILED)) return self.finish_state(peer_state) try: peer_state.file = open(peer_state.filepath, 'rb') peer_state.filesize = os.stat(peer_state.filepath)[stat.ST_SIZE] peer_state.packetnum = 0 peer_state.state = state.STATE_SEND l.info('Serving file %s to host %s...' % (filename, self.client_address[0]), extra=peer_state.extra(notify.TRANSFER_STARTED)) # Only set options if not running in RFC1350 compliance mode # and when option were received. if not self.server.strict_rfc1350 and len(opts): opts = proto.TFTPHelper.parse_options(opts) if opts: blksize = opts[proto.TFTP_OPTION_BLKSIZE] windowsize = opts[proto.TFTP_OPTION_WINDOWSIZE] #max_window_size = int( # get_max_udp_datagram_size() / # proto.TFTPHelper.get_data_size(blksize)) #if windowsize > max_window_size: # l.info('Restricting window size to %d to fit UDP.' % # max_window_size) # opts[proto.TFTP_OPTION_WINDOWSIZE] = max_window_size # HOOK: this is where we should check that we accept # the options requested by the client. peer_state.state = state.STATE_SEND_OACK peer_state.set_opts(opts) else: peer_state.file.close() peer_state.state = state.STATE_ERROR peer_state.error = proto.ERROR_OPTION_NEGOCIATION except IOError as e: peer_state.state = state.STATE_ERROR if e.errno == errno.ENOENT: peer_state.error = proto.ERROR_FILE_NOT_FOUND l.warning('Client requested non-existent file %s' % filename, extra=peer_state.extra(notify.TRANSFER_FAILED)) elif e.errno == errno.EACCES or e.errno == errno.EPERM: peer_state.error = proto.ERROR_ACCESS_VIOLATION l.error('Client requested inaccessible file %s' % filename, extra=peer_state.extra(notify.TRANSFER_FAILED)) else: peer_state.error = proto.ERROR_UNDEF l.error('Unknown error while accessing file %s' % filename, extra=peer_state.extra(notify.TRANSFER_FAILED)) return self.finish_state(peer_state)
def get(self, args): """ Implements the GET command to retrieve a file from the server. Args: args (list): the list of arguments passed to the command. Returns: True or False depending on the success of the operation. """ if len(args) < 1 or len(args) > 2: print('Usage: get [-f] <filename>') return False filepath = args[0] overwrite = False if len(args) == 2: filepath = args[1] if args[0] == '-f': overwrite = True (_, filename) = os.path.split(filepath) # First, check we're not going to overwrite an existing file if not overwrite: try: open(filename) print('Error: local file {} already exists!'.format(filename)) print('Use get -f to overwrite the local file.') return False except IOError: pass self.PTFTP_STATE = state.TFTPState(self.peer, proto.OP_RRQ, '', filepath, self.transfer_mode, not self.rfc1350) # Then, before sending anything to the server, open the file # for writing try: # We don't want tempfile to automatically delete the temporary # file on close() as we have to copy its content to the destination # file first. We'll handle it's deletion on our own. self.PTFTP_STATE.file = tempfile.NamedTemporaryFile(delete=False) self.PTFTP_STATE.packetnum = 1 self.PTFTP_STATE.state = state.STATE_RECV except IOError as e: print('Error: {}'.format(os.strerror(e.errno))) print('Can\'t write to temporary file {}!'.format( self.PTFTP_STATE.file.name)) return False opts = dict(self.opts) # When not running in RFC1350 compliance mode, append tsize: 0 # to the list of options in the request to get the requested # file size back in the OACK. if not self.rfc1350: opts[proto.TFTP_OPTION_TSIZE] = 0 # Everything's OK, let's go print("Retrieving '%s' from the remote host..." % filename) packet = proto.TFTPHelper.createRRQ(filepath, self.transfer_mode, opts) transfer_start = datetime.today() self.sock.send(packet, self.peer) self.handle() transfer_time = datetime.today() - transfer_start if self.error: error, errmsg = self.error if error and errmsg: print('Error: {}'.format(errmsg)) # Remove the temporary file on error. The destionation file, # if it already existed, is left untouched. self.PTFTP_STATE.file.close() os.remove(self.PTFTP_STATE.file.name) return False # Copy the temporary file to its final destination try: shutil.copy(self.PTFTP_STATE.file.name, filename) except IOError as e: print('Error: {}'.format(os.strerror(e.errno))) print('Can\'t copy temporary file to local file {}!'.format( filename)) return False print('Transfer complete, {} bytes ({:.2f} kB/s)'.format( self.PTFTP_STATE.filesize, self.__get_speed(self.PTFTP_STATE.filesize, transfer_time))) self.PTFTP_STATE.file.close() os.remove(self.PTFTP_STATE.file.name) return True
def serveRRQ(self, op, request): """ Serves RRQ packets (GET requests). Args: op (integer): the TFTP opcode. request (string): the TFTP packet without its opcode. Returns: A response packet (as a string) or None if the request is ignored for some reason. """ try: filenameOrig, mode, opts = proto.TFTPHelper.parseRRQ(request) except SyntaxError: # Ignore malformed RRQ requests return None # we keep the filenameOrig for dynamic handler # some clients request "\" and not "/" in their pathes if os.name != 'nt': filename = filenameOrig.replace('\\', '/') else: filename = filenameOrig.replace('/', '\\') # absolute path requests are always relative to the tftp root directory # if the client does something nasty we get it some lines down. if filename and filename[0] == "/": filename = filename[1:] peer_state = state.TFTPState(self.client_address, op, self.server.root, filename, mode, not self.server.strict_rfc1350) if not peer_state.filepath.startswith(self.server.root): peer_state.state = state.STATE_ERROR peer_state.error = proto.ERROR_ACCESS_VIOLATION l.warning('Out-of-jail path requested: %s!' % filename, extra=peer_state.extra(notify.TRANSFER_FAILED)) return self.finish_state(peer_state) try: # If the file exists, open it # TODO: Windows clients request case insensitive, which may be a problem on *nix servers if os.path.isfile(peer_state.filepath) and\ os.access(peer_state.filepath, os.R_OK): peer_state.file = open(peer_state.filepath, 'rb') peer_state.filesize = os.stat( peer_state.filepath)[stat.ST_SIZE] else: # The file doen't exist, try the dynamic_file_handler # if it is set if hasattr(self, 'dynamic_file_handler') and\ self.dynamic_file_handler is not None: # we send the original requested filename to the handler peer_state.file, peer_state.filesize = self.dynamic_file_handler( filenameOrig) else: raise IOError('Cannot access file: %s' % filenameOrig) peer_state.packetnum = 0 peer_state.state = state.STATE_SEND l.info('Serving file %s to host %s...' % (filename, self.client_address[0]), extra=peer_state.extra(notify.TRANSFER_STARTED)) # Only set options if not running in RFC1350 compliance mode # and when option were received. if not self.server.strict_rfc1350 and len(opts): opts = proto.TFTPHelper.parse_options(opts) if opts: # HOOK: this is where we should check that we accept # the options requested by the client. peer_state.state = state.STATE_SEND_OACK peer_state.set_opts(opts) else: peer_state.file.close() peer_state.state = state.STATE_ERROR peer_state.error = proto.ERROR_OPTION_NEGOCIATION except IOError, e: peer_state.state = state.STATE_ERROR if e.errno == errno.ENOENT: peer_state.error = proto.ERROR_FILE_NOT_FOUND l.warning('Client requested non-existent file %s' % filename, extra=peer_state.extra(notify.TRANSFER_FAILED)) elif e.errno == errno.EACCES or e.errno == errno.EPERM: peer_state.error = proto.ERROR_ACCESS_VIOLATION l.error('Client requested inaccessible file %s' % filename, extra=peer_state.extra(notify.TRANSFER_FAILED)) else: peer_state.error = proto.ERROR_UNDEF l.error('Unknown error while accessing file %s' % filename, extra=peer_state.extra(notify.TRANSFER_FAILED))