Beispiel #1
0
class CustomFTP(FTP):
   def ftp_PASV(self):
      # if we have a DTP port set up, lose it.
      if self.dtpFactory is not None:
          # cleanupDTP sets dtpFactory to none.  Later we'll do
          # cleanup here or something.
          self.cleanupDTP()
      self.dtpFactory = DTPFactory(pi=self)
      self.dtpFactory.setTimeout(self.dtpTimeout)
      self.dtpPort = self.getDTPPort(self.dtpFactory)

      if self.factory.passivePublicIp is not None:
         # use explicit public IP for passive mode (when behind load-balancer or such)
         host = self.factory.passivePublicIp
         log.msg("using explicit public IP %s" % host)
      else:
         # use transport IP
         host = self.transport.getHost().host
         log.msg("using transport IP %s" % host)

      port = self.dtpPort.getHost().port
      self.reply(ENTERING_PASV_MODE, encodeHostPort(host, port))
      return self.dtpFactory.deferred.addCallback(lambda ign: None)
Beispiel #2
0
    def ftp_PORT(self, address):
        addr = map(int, address.split(','))
        ip = '%d.%d.%d.%d' % tuple(addr[:4])
        port = addr[4] << 8 | addr[5]

        # if we have a DTP port set up, lose it.
        if self.dtpFactory is not None:
            self.cleanupDTP()

        self.dtpFactory = DTPFactory(pi=self,
                                     peerHost=self.transport.getPeer().host)
        self.dtpFactory.setTimeout(self.dtpTimeout)
        self.dtpPort = reactor.connectTCP(ip, port, self.dtpFactory)

        def connected(ignored):
            self.reply(ENTERING_PORT_MODE)
            if self.tls_mode:
                self.dtpInstance.transport.startTLS(self.factory.cert_options)

        def connFailed(err):
            err.trap(PortConnectionError)
            return CANT_OPEN_DATA_CNX

        return self.dtpFactory.deferred.addCallbacks(connected, connFailed)
Beispiel #3
0
    def ftp_PORT(self, address):
        addr = map(int, address.split(','))
        ip = '%d.%d.%d.%d' % tuple(addr[:4])
        port = addr[4] << 8 | addr[5]

        # if we have a DTP port set up, lose it.
        if self.dtpFactory is not None:
            self.cleanupDTP()

        self.dtpFactory = DTPFactory(pi=self, peerHost=self.transport.getPeer().host)
        self.dtpFactory.setTimeout(self.dtpTimeout)
        self.dtpPort = reactor.connectTCP(ip, port, self.dtpFactory)

        def connected(ignored):
            self.reply(ENTERING_PORT_MODE)
            if self.tls_mode:
                self.dtpInstance.transport.startTLS(self.factory.cert_options)
        def connFailed(err):
            err.trap(PortConnectionError)
            return CANT_OPEN_DATA_CNX
        return self.dtpFactory.deferred.addCallbacks(connected, connFailed)
Beispiel #4
0
class SwftpFTPProtocol(FTP, object):
    _connCountMap = defaultdict(int)
    maxConnectionsPerUser = 10

    PUBLIC_COMMANDS = ['FEAT', 'QUIT', 'AUTH']

    tls_mode = False

    def ftp_AUTH(self, *args, **kwargs):
        mode, = args
        if mode == 'TLS':
            msg("Initiated TLS")
            self.reply(AUTH_OK)
            self.transport.startTLS(self.factory.cert_options)
            return
        return defer.fail(CmdNotImplementedError('AUTH %s' % mode))

    def ftp_PBSZ(self, *args, **kwargs):
        return CMD_OK

    def ftp_PROT(self, *args, **kwargs):
        cmd, = args
        if cmd == 'P':
            self.tls_mode = True
            return CMD_OK

    def connectionMade(self, *args, **kwargs):
        log.msg(metric='num_clients')
        return super(SwftpFTPProtocol, self).connectionMade(*args, **kwargs)

    def connectionLost(self, *args, **kwargs):
        log.msg(metric='num_clients', count=-1)

        if self.shell:
            username = self.shell.username()
            msg("User Disconnected (%s) [%s/%s]" % (
                username,
                self._connCountMap[username],
                self.maxConnectionsPerUser,
            ))
            self._connCountMap[username] -= 1
            # To avoid a slow memory leak
            if self._connCountMap[username] == 0:
                del self._connCountMap[username]
        return super(SwftpFTPProtocol, self).connectionLost(*args, **kwargs)

    def ftp_PASS(self, *args, **kwargs):
        # Check to see if the user has too many connections
        d = super(SwftpFTPProtocol, self).ftp_PASS(*args, **kwargs)

        def pass_cb(res):
            username = self.shell.username()
            self._connCountMap[username] += 1
            msg("User Connected (%s) [%s/%s]" % (
                username,
                self._connCountMap[username],
                self.maxConnectionsPerUser,
            ))
            if self.maxConnectionsPerUser != 0 and \
                    self._connCountMap[username] > self.maxConnectionsPerUser:
                msg("Too Many Connections For User (%s) [%s/%s]" % (
                    username,
                    self._connCountMap[username],
                    self.maxConnectionsPerUser,
                ))
                self.sendLine(RESPONSE[TOO_MANY_CONNECTIONS])
                self.transport.loseConnection()
            return res

        d.addCallback(pass_cb)
        return d

    def ftp_LIST(self, path=''):
        # ignore special flags for command LIST
        keys = ['-a', '-l', '-la', '-al']
        segm = path.split()
        path = " ".join(s for s in segm if s.lower() not in keys)

        return super(SwftpFTPProtocol, self).ftp_LIST(path)

    def ftp_NLST(self, path=''):
        """
        Overwrite for fix http://twistedmatrix.com/trac/ticket/4258
        """
        return super(SwftpFTPProtocol, self).ftp_NLST(path)

    def ftp_PASV(self):
        d = super(SwftpFTPProtocol, self).ftp_PASV()

        def dtp_connect_timeout_eb(failure):
            failure.trap(PortConnectionError)

        if self.tls_mode:

            def cb(res):
                self.dtpInstance.transport.startTLS(self.factory.cert_options)

            d.addCallback(cb)

        return d.addErrback(dtp_connect_timeout_eb)

    def ftp_PORT(self, address):
        addr = map(int, address.split(','))
        ip = '%d.%d.%d.%d' % tuple(addr[:4])
        port = addr[4] << 8 | addr[5]

        # if we have a DTP port set up, lose it.
        if self.dtpFactory is not None:
            self.cleanupDTP()

        self.dtpFactory = DTPFactory(pi=self,
                                     peerHost=self.transport.getPeer().host)
        self.dtpFactory.setTimeout(self.dtpTimeout)
        self.dtpPort = reactor.connectTCP(ip, port, self.dtpFactory)

        def connected(ignored):
            self.reply(ENTERING_PORT_MODE)
            if self.tls_mode:
                self.dtpInstance.transport.startTLS(self.factory.cert_options)

        def connFailed(err):
            err.trap(PortConnectionError)
            return CANT_OPEN_DATA_CNX

        return self.dtpFactory.deferred.addCallbacks(connected, connFailed)

    def ftp_REST(self, value):
        if self.dtpInstance is None:
            raise BadCmdSequenceError('PORT or PASV required before RETR')

        try:
            value = int(value)
            if value < 0:
                raise ValueError
        except ValueError:
            raise CmdArgSyntaxError('Value must be nonnegative integer')
        else:
            self.dtpInstance.rest_offset = value

        return (REQ_FILE_ACTN_PENDING_FURTHER_INFO, )

    def cleanupDTP(self):
        """
        Overwrite cleanupDTP() for fix socket leak
        (see http://twistedmatrix.com/trac/ticket/5367)
        """
        transport = None
        if self.dtpInstance is not None:
            if self.dtpInstance.transport is not None:
                transport = self.dtpInstance.transport

        super(SwftpFTPProtocol, self).cleanupDTP()

        if transport:
            transport.abortConnection()
Beispiel #5
0
class SwftpFTPProtocol(FTP, object):
    _connCountMap = defaultdict(int)
    maxConnectionsPerUser = 10

    PUBLIC_COMMANDS = ['FEAT', 'QUIT', 'AUTH']

    tls_mode = False

    def ftp_AUTH(self, *args, **kwargs):
        mode, = args
        if mode == 'TLS':
            msg("Initiated TLS")
            self.reply(AUTH_OK)
            self.transport.startTLS(self.factory.cert_options)
            return
        return defer.fail(CmdNotImplementedError('AUTH %s' % mode))

    def ftp_PBSZ(self, *args, **kwargs):
        return CMD_OK

    def ftp_PROT(self, *args, **kwargs):
        cmd, = args
        if cmd == 'P':
            self.tls_mode = True
            return CMD_OK

    def connectionMade(self, *args, **kwargs):
        log.msg(metric='num_clients')
        return super(SwftpFTPProtocol, self).connectionMade(*args, **kwargs)

    def connectionLost(self, *args, **kwargs):
        log.msg(metric='num_clients', count=-1)

        if self.shell:
            username = self.shell.username()
            msg("User Disconnected (%s) [%s/%s]" % (
                username,
                self._connCountMap[username],
                self.maxConnectionsPerUser,
                ))
            self._connCountMap[username] -= 1
            # To avoid a slow memory leak
            if self._connCountMap[username] == 0:
                del self._connCountMap[username]
        return super(SwftpFTPProtocol, self).connectionLost(*args, **kwargs)

    def ftp_PASS(self, *args, **kwargs):
        # Check to see if the user has too many connections
        d = super(SwftpFTPProtocol, self).ftp_PASS(*args, **kwargs)

        def pass_cb(res):
            username = self.shell.username()
            self._connCountMap[username] += 1
            msg("User Connected (%s) [%s/%s]" % (
                username,
                self._connCountMap[username],
                self.maxConnectionsPerUser,
                ))
            if self.maxConnectionsPerUser != 0 and \
                    self._connCountMap[username] > self.maxConnectionsPerUser:
                msg("Too Many Connections For User (%s) [%s/%s]" % (
                    username,
                    self._connCountMap[username],
                    self.maxConnectionsPerUser,
                    ))
                self.sendLine(RESPONSE[TOO_MANY_CONNECTIONS])
                self.transport.loseConnection()
            return res

        d.addCallback(pass_cb)
        return d

    def ftp_LIST(self, path=''):
        # ignore special flags for command LIST
        keys = ['-a', '-l', '-la', '-al']
        segm = path.split()
        path = " ".join(s for s in segm if s.lower() not in keys)

        return super(SwftpFTPProtocol, self).ftp_LIST(path)

    def ftp_NLST(self, path=''):
        """
        Overwrite for fix http://twistedmatrix.com/trac/ticket/4258
        """
        return super(SwftpFTPProtocol, self).ftp_NLST(path)

    def ftp_PASV(self):
        d = super(SwftpFTPProtocol, self).ftp_PASV()

        def dtp_connect_timeout_eb(failure):
            failure.trap(PortConnectionError)

        if self.tls_mode:
            def cb(res):
                self.dtpInstance.transport.startTLS(self.factory.cert_options)
            d.addCallback(cb)

        return d.addErrback(dtp_connect_timeout_eb)

    def ftp_PORT(self, address):
        addr = map(int, address.split(','))
        ip = '%d.%d.%d.%d' % tuple(addr[:4])
        port = addr[4] << 8 | addr[5]

        # if we have a DTP port set up, lose it.
        if self.dtpFactory is not None:
            self.cleanupDTP()

        self.dtpFactory = DTPFactory(pi=self, peerHost=self.transport.getPeer().host)
        self.dtpFactory.setTimeout(self.dtpTimeout)
        self.dtpPort = reactor.connectTCP(ip, port, self.dtpFactory)

        def connected(ignored):
            self.reply(ENTERING_PORT_MODE)
            if self.tls_mode:
                self.dtpInstance.transport.startTLS(self.factory.cert_options)
        def connFailed(err):
            err.trap(PortConnectionError)
            return CANT_OPEN_DATA_CNX
        return self.dtpFactory.deferred.addCallbacks(connected, connFailed)

    def ftp_REST(self, value):
        if self.dtpInstance is None:
            raise BadCmdSequenceError('PORT or PASV required before RETR')

        try:
            value = int(value)
            if value < 0:
                raise ValueError
        except ValueError:
            raise CmdArgSyntaxError('Value must be nonnegative integer')
        else:
            self.dtpInstance.rest_offset = value

        return (REQ_FILE_ACTN_PENDING_FURTHER_INFO, )

    def cleanupDTP(self):
        """
        Overwrite cleanupDTP() for fix socket leak
        (see http://twistedmatrix.com/trac/ticket/5367)
        """
        transport = None
        if self.dtpInstance is not None:
            if self.dtpInstance.transport is not None:
                transport = self.dtpInstance.transport

        super(SwftpFTPProtocol, self).cleanupDTP()

        if transport:
            transport.abortConnection()