Exemple #1
0
    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
Exemple #2
0
    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
Exemple #3
0
    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
Exemple #4
0
    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)
Exemple #5
0
    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)
Exemple #6
0
    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
Exemple #7
0
    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))