Пример #1
0
    def readLink(self, path):
        """
        Find the root of a set of symbolic links.

        This method returns the target of the link, or a Deferred that
        returns the same.

        @type path: L{bytes}
        @param path: the path of the symlink to read.
        """
        d = self._sendRequest(FXP_READLINK, NS(path))
        return d.addCallback(self._cbRealPath)
Пример #2
0
    def test_failedAuthentication(self):
        """
        When provided with invalid authentication details, the server should
        respond by sending a MSG_USERAUTH_FAILURE message which states whether
        the authentication was partially successful, and provides other, open
        options for authentication.

        See RFC 4252, Section 5.1.
        """
        # packet = username, next_service, authentication type, FALSE, password
        packet = NS('foo') + NS('none') + NS('password') + chr(0) + NS('bar')
        d = self.authServer.ssh_USERAUTH_REQUEST(packet)

        def check(ignored):
            # Check that the server reports the failure, including 'password'
            # as a valid authentication type.
            self.assertEqual(
                self.authServer.transport.packets,
                [(userauth.MSG_USERAUTH_FAILURE, NS('password') + chr(0))])

        return d.addCallback(check)
Пример #3
0
    def _ebMaybeBadAuth(self, reason):
        """
        An intermediate errback.  If the reason is
        error.NotEnoughAuthentication, we send a MSG_USERAUTH_FAILURE, but
        with the partial success indicator set.

        @type reason: L{twisted.python.failure.Failure}
        """
        reason.trap(error.NotEnoughAuthentication)
        self.transport.sendPacket(
            MSG_USERAUTH_FAILURE,
            NS(b','.join(self.supportedAuthentications)) + b'\xff')
 def test_old_publickey_getPublicKey(self):
     """
     Old SSHUserAuthClients returned strings of public key blobs from
     getPublicKey().  Test that a Deprecation warning is raised but the key is
     verified correctly.
     """
     oldAuth = OldClientAuth('foo', FakeTransport.Service())
     oldAuth.transport = FakeTransport(None)
     oldAuth.transport.sessionID = 'test'
     oldAuth.serviceStarted()
     oldAuth.transport.packets = []
     self.assertWarns(
         DeprecationWarning, "Returning a string from "
         "SSHUserAuthClient.getPublicKey() is deprecated since "
         "Twisted 9.0.  Return a keys.Key() instead.", userauth.__file__,
         oldAuth.tryAuth, 'publickey')
     self.assertEquals(
         oldAuth.transport.packets,
         [(userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') +
           NS('publickey') + '\x00' + NS('ssh-rsa') +
           NS(keys.Key.fromString(keydata.publicRSA_openssh).blob()))])
Пример #5
0
    def removeDirectory(self, path):
        """
        Remove a directory (non-recursively)

        It is an error to remove a directory that has files or directories in
        it.

        This method returns a Deferred that is called back when it is removed.

        @param path: the directory to remove.
        """
        return self._sendRequest(FXP_RMDIR, NS(path))
Пример #6
0
    def test_failedPasswordAuthentication(self):
        """
        When provided with invalid authentication details, the server should
        respond by sending a MSG_USERAUTH_FAILURE message which states whether
        the authentication was partially successful, and provides other, open
        options for authentication.

        See RFC 4252, Section 5.1.
        """
        # packet = username, next_service, authentication type, FALSE, password
        packet = b''.join(
            [NS(b'foo'),
             NS(b'none'),
             NS(b'password'),
             chr(0),
             NS(b'bar')])
        self.authServer.clock = task.Clock()
        d = self.authServer.ssh_USERAUTH_REQUEST(packet)
        self.assertEqual(self.authServer.transport.packets, [])
        self.authServer.clock.advance(2)
        return d.addCallback(self._checkFailed)
Пример #7
0
    def test_successfulPasswordAuthentication(self):
        """
        When provided with correct password authentication information, the
        server should respond by sending a MSG_USERAUTH_SUCCESS message with
        no other data.

        See RFC 4252, Section 5.1.
        """
        packet = b''.join(
            [NS(b'foo'),
             NS(b'none'),
             NS(b'password'),
             chr(0),
             NS(b'foo')])
        d = self.authServer.ssh_USERAUTH_REQUEST(packet)

        def check(ignored):
            self.assertEqual(self.authServer.transport.packets,
                             [(userauth.MSG_USERAUTH_SUCCESS, b'')])

        return d.addCallback(check)
Пример #8
0
    def realPath(self, path):
        """
        Convert any path to an absolute path.

        This method returns the absolute path as a string, or a Deferred
        that returns the same.

        @type path: L{bytes}
        @param path: the path to convert as a string.
        """
        d = self._sendRequest(FXP_REALPATH, NS(path))
        return d.addCallback(self._cbRealPath)
Пример #9
0
    def test_USERAUTH_FAILURE_sorting(self):
        """
        ssh_USERAUTH_FAILURE should sort the methods by their position
        in SSHUserAuthClient.preferredOrder.  Methods that are not in
        preferredOrder should be sorted at the end of that list.
        """
        def auth_firstmethod():
            self.authClient.transport.sendPacket(255, 'here is data')

        def auth_anothermethod():
            self.authClient.transport.sendPacket(254, 'other data')
            return True

        self.authClient.auth_firstmethod = auth_firstmethod
        self.authClient.auth_anothermethod = auth_anothermethod

        self.authClient.ssh_USERAUTH_FAILURE(
            NS('afirstmethod,password') + '\x00')
        # should send password packet
        self.assertEquals(self.authClient.transport.packets[-1],
                          (userauth.MSG_USERAUTH_REQUEST, NS('foo') +
                           NS('nancy') + NS('password') + '\x00' + NS('foo')))
        self.authClient.ssh_USERAUTH_FAILURE(
            NS('firstmethod,anothermethod,password') + '\xff')
        self.assertEquals(self.authClient.transport.packets[-2:],
                          [(255, 'here is data'), (254, 'other data')])
Пример #10
0
    def auth_publickey(self, packet):
        """
        Public key authentication.  Payload::
            byte has signature
            string algorithm name
            string key blob
            [string signature] (if has signature is True)

        Create a SSHPublicKey credential and verify it using our portal.
        """
        hasSig = ord(packet[0])
        algName, blob, rest = getNS(packet[1:], 2)
        pubKey = keys.Key.fromString(blob)
        signature = hasSig and getNS(rest)[0] or None
        if hasSig:
            b = (NS(self.transport.sessionID) + chr(MSG_USERAUTH_REQUEST) +
                NS(self.user) + NS(self.nextService) + NS('publickey') +
                chr(hasSig) +  NS(pubKey.sshType()) + NS(blob))
            c = credentials.SSHPrivateKey(self.user, algName, blob, b,
                    signature)
            return self.portal.login(c, None, interfaces.IConchUser)
        else:
            c = credentials.SSHPrivateKey(self.user, algName, blob, None, None)
            return self.portal.login(c, None,
                    interfaces.IConchUser).addErrback(self._ebCheckKey,
                            packet[1:])
Пример #11
0
    def test_USERAUTH_FAILURE_sorting(self):
        """
        ssh_USERAUTH_FAILURE should sort the methods by their position
        in SSHUserAuthClient.preferredOrder.  Methods that are not in
        preferredOrder should be sorted at the end of that list.
        """
        def auth_firstmethod():
            self.authClient.transport.sendPacket(255, b'here is data')

        def auth_anothermethod():
            self.authClient.transport.sendPacket(254, b'other data')
            return True

        self.authClient.auth_firstmethod = auth_firstmethod
        self.authClient.auth_anothermethod = auth_anothermethod

        # although they shouldn't get called, method callbacks auth_* MUST
        # exist in order for the test to work properly.
        self.authClient.ssh_USERAUTH_FAILURE(
            NS(b'anothermethod,password') + b'\x00')
        # should send password packet
        self.assertEqual(
            self.authClient.transport.packets[-1],
            (userauth.MSG_USERAUTH_REQUEST, NS(b'foo') + NS(b'nancy') +
             NS(b'password') + b'\x00' + NS(b'foo')))
        self.authClient.ssh_USERAUTH_FAILURE(
            NS(b'firstmethod,anothermethod,password') + b'\xff')
        self.assertEqual(self.authClient.transport.packets[-2:],
                         [(255, b'here is data'), (254, b'other data')])
Пример #12
0
    def auth_publickey(self, packet):
        """
        Public key authentication.  Payload::
            byte has signature
            string algorithm name
            string key blob
            [string signature] (if has signature is True)

        Create a SSHPublicKey credential and verify it using our portal.
        """
        hasSig = ord(packet[0:1])
        algName, blob, rest = getNS(packet[1:], 2)

        try:
            pubKey = keys.Key.fromString(blob)
        except keys.BadKeyError:
            error = "Unsupported key type {} or bad key".format(
                algName.decode("ascii"))
            self._log.error(error)
            return defer.fail(UnauthorizedLogin(error))

        signature = hasSig and getNS(rest)[0] or None
        if hasSig:
            b = (NS(self.transport.sessionID) + bytes(
                (MSG_USERAUTH_REQUEST, )) + NS(self.user) +
                 NS(self.nextService) + NS(b"publickey") + bytes(
                     (hasSig, )) + NS(pubKey.sshType()) + NS(blob))
            c = credentials.SSHPrivateKey(self.user, algName, blob, b,
                                          signature)
            return self.portal.login(c, None, interfaces.IConchUser)
        else:
            c = credentials.SSHPrivateKey(self.user, algName, blob, None, None)
            return self.portal.login(c, None,
                                     interfaces.IConchUser).addErrback(
                                         self._ebCheckKey, packet[1:])
Пример #13
0
    def setAttrs(self, path, attrs):
        """
        Set the attributes for the path.

        This method returns when the attributes are set or a Deferred that is
        called back when they are.

        @param path: the path to set attributes for as a string.
        @param attrs: a dictionary in the same format as the attrs argument to
        openFile.
        """
        data = NS(path) + self._packAttributes(attrs)
        return self._sendRequest(FXP_SETSTAT, data)
Пример #14
0
    def channelOpen(self, _):
        def ptyReqFailed(reason):
            # TODO(vladum): Why is this never called? Looks like the Transport
            # received the error (at least the packet integrity ones).
            err("SSH PTY Request failed")
            self.reason = reason
            self.conn.sendClose(self)

        modes = pack("<B", 0x00) # only TTY_OP_END
        win_size = (0, 0, 0, 0)  # 0s are ignored
        pty_req_data = packRequest_pty_req('vt100', win_size, modes)
        d = self.conn.sendRequest(self, 'pty-req', pty_req_data, wantReply=True)
        #Set all the env variables we've got
        for key, value in self.env:
            d.addCallback(
                lambda _: self.conn.sendRequest(self, 'env', NS(key), NS(value), wantReply=True)
            )
        d.addCallback(
            # send command after we get the pty
            lambda _: self.conn.sendRequest(self, 'exec', NS(self.command))
        )
        d.addErrback(ptyReqFailed)
Пример #15
0
 def agentc_SIGN_REQUEST(self, data):
     """
     Data is a structure with a reference to an already added key object and
     some data that the clients wants signed with that key.  If the key
     object wasn't loaded, return AGENT_FAILURE, else return the signature.
     """
     blob, data = getNS(data)
     if blob not in self.factory.keys:
         return self.sendResponse(AGENT_FAILURE, '')
     signData, data = getNS(data)
     assert data == '\000\000\000\000'
     self.sendResponse(AGENT_SIGN_RESPONSE,
                       NS(self.factory.keys[blob][0].sign(signData)))
Пример #16
0
    def _cbGenericAnswers(self, responses):
        """
        Called back when we are finished answering keyboard-interactive
        questions.  Send the info back to the server in a
        MSG_USERAUTH_INFO_RESPONSE.

        @param responses: a list of C{str} responses
        @type responses: C{list}
        """
        data = struct.pack('!L', len(responses))
        for r in responses:
            data += NS(r.encode('UTF8'))
        self.transport.sendPacket(MSG_USERAUTH_INFO_RESPONSE, data)
Пример #17
0
    def ssh_KEX_DH_GEX_REQUEST_OLD(self, packet):
        """
        This represents two different key exchange methods that share the
        same integer value.

        KEXDH_INIT (for diffie-hellman-group1-sha1 exchanges) payload::

                integer e (the client's Diffie-Hellman public key)

            We send the KEXDH_REPLY with our host key and signature.

        KEX_DH_GEX_REQUEST_OLD (for diffie-hellman-group-exchange-sha1)
        payload::

                integer ideal (ideal size for the Diffie-Hellman prime)

            We send the KEX_DH_GEX_GROUP message with the group that is
            closest in size to ideal.

        If we were told to ignore the next key exchange packet by
        ssh_KEXINIT, drop it on the floor and return.
        """
        if self.ignoreNextPacket:
            self.ignoreNextPacket = 0
            return
        if self.kexAlg == 'diffie-hellman-group1-sha1':
            # this is really KEXDH_INIT
            clientDHpublicKey, foo = getMP(packet)
            y = Util.number.getRandomNumber(512, randbytes.secureRandom)
            serverDHpublicKey = _MPpow(DH_GENERATOR, y, DH_PRIME)
            sharedSecret = _MPpow(clientDHpublicKey, y, DH_PRIME)
            h = sha1()
            h.update(NS(self.otherVersionString))
            h.update(NS(self.ourVersionString))
            h.update(NS(self.otherKexInitPayload))
            h.update(NS(self.ourKexInitPayload))
            h.update(NS(self.factory.publicKeys[self.keyAlg].blob()))
            h.update(MP(clientDHpublicKey))
            h.update(serverDHpublicKey)
            h.update(sharedSecret)
            exchangeHash = h.digest()
            self.sendPacket(
                MSG_KEXDH_REPLY,
                NS(self.factory.publicKeys[self.keyAlg].blob()) +
                serverDHpublicKey +
                NS(self.factory.privateKeys[self.keyAlg].sign(exchangeHash)))
            self._keySetup(sharedSecret, exchangeHash)
        elif self.kexAlg == 'diffie-hellman-group-exchange-sha1':
            self.dhGexRequest = packet
            ideal = struct.unpack('>L', packet)[0]
            self.g, self.p = self.factory.getDHPrime(ideal)
            self.sendPacket(MSG_KEX_DH_GEX_GROUP, MP(self.p) + MP(self.g))
        else:
            raise error.ConchError('bad kexalg: %s' % self.kexAlg)
Пример #18
0
    def extendedRequest(self, request, data):
        """
        Make an extended request of the server.

        The method returns a Deferred that is called back with
        the result of the extended request.

        @type request: L{bytes}
        @param request: the name of the extended request to make.
        @type data: L{bytes}
        @param data: any other data that goes along with the request.
        """
        return self._sendRequest(FXP_EXTENDED, NS(request) + data)
Пример #19
0
 def channelOpen(self, ignored):
     """
     Create a pty by sending a pty-req to the server
     """
     term = 'xterm'
     winSize = (25, 80, 0, 0)
     ptyReqData = session.packRequest_pty_req(term, winSize, '')
     self.conn.sendRequest(self, 'pty-req', ptyReqData)
     command = self.conn.sendRequest(self,
                                     'exec',
                                     NS(self._command),
                                     wantReply=True)
     command.addCallbacks(self._execSuccess, self._execFailure)
Пример #20
0
 def test_invalid_USERAUTH_INFO_RESPONSE_not_enough_data(self):
     """
     If ssh_USERAUTH_INFO_RESPONSE gets an invalid packet,
     the user authentication should fail.
     """
     packet = (NS('foo') + NS('none') + NS('keyboard-interactive') +
               NS('') + NS(''))
     d = self.authServer.ssh_USERAUTH_REQUEST(packet)
     self.authServer.ssh_USERAUTH_INFO_RESPONSE(
         NS('\x00\x00\x00\x00' + NS('hi')))
     return d.addCallback(self._checkFailed)
Пример #21
0
    def makeDirectory(self, path, attrs):
        """
        Make a directory.

        This method returns a Deferred that is called back when it is
        created.

        @type path: L{bytes}
        @param path: the name of the directory to create as a string.

        @param attrs: a dictionary of attributes to create the directory
        with.  Its meaning is the same as the attrs in the openFile method.
        """
        return self._sendRequest(FXP_MKDIR, NS(path) + self._packAttributes(attrs))
Пример #22
0
    def test_tooManyAttempts(self):
        """
        Test that the server disconnects if the client fails authentication
        too many times.
        """
        packet = b''.join(
            [NS(b'foo'),
             NS(b'none'),
             NS(b'password'), b'\0',
             NS(b'bar')])
        self.authServer.clock = task.Clock()
        for i in range(21):
            d = self.authServer.ssh_USERAUTH_REQUEST(packet)
            self.authServer.clock.advance(2)

        def check(ignored):
            self.assertEqual(
                self.authServer.transport.packets[-1],
                (transport.MSG_DISCONNECT, b'\x00' * 3 + bytes(
                    (transport.DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, )) +
                 NS(b"too many bad auths") + NS(b'')))

        return d.addCallback(check)
Пример #23
0
    def channelOpen(self, ignoredData):
        req = packRequest_pty_req(self.conn.client.term, self.conn.client.size,
                                  "")
        self.conn.sendRequest(self, "pty-req", req)

        d = self.conn.sendRequest(self,
                                  'exec',
                                  NS(" ".join(command)),
                                  wantReply=1)

        @d.addCallback
        def cb(chaff):
            other = self.conn.client.proxy
            self.proxy.setPeer(other)
            other.setPeer(self.proxy)
Пример #24
0
    def getAttrs(self, path, followLinks=0):
        """
        Return the attributes for the given path.

        This method returns a dictionary in the same format as the attrs
        argument to openFile or a Deferred that is called back with same.

        @param path: the path to return attributes for as a string.
        @param followLinks: a boolean.  if it is True, follow symbolic links
        and return attributes for the real path at the base.  if it is False,
        return attributes for the specified path.
        """
        if followLinks: m = FXP_STAT
        else: m = FXP_LSTAT
        return self._sendRequest(m, NS(path))
Пример #25
0
    def channelOpen(self, whatever):
        """
        Called when the channel is opened.  "whatever" is any data that the
        other side sent us when opening the channel.

        @type whatever: L{bytes}
        """
        yield self.conn.sendRequest(self,
                                    "subsystem",
                                    NS("sftp"),
                                    wantReply=True)

        client = SFTPClient()
        client.makeConnection(self)
        self.dataReceived = client.dataReceived
        self.conn.notifyClientIsReady(client)
Пример #26
0
 def test_keyboardInteractive(self):
     """
     Make sure that the client can authenticate with the keyboard
     interactive method.
     """
     self.authClient.ssh_USERAUTH_PK_OK_keyboard_interactive(
         NS(b'') + NS(b'') + NS(b'') + b'\x00\x00\x00\x01' +
         NS(b'Password: '******'\x00')
     self.assertEqual(self.authClient.transport.packets[-1],
                      (userauth.MSG_USERAUTH_INFO_RESPONSE,
                       b'\x00\x00\x00\x02' + NS(b'foo') + NS(b'foo')))
Пример #27
0
 def test_failedPAMAuthentication(self):
     """
     Test that keyboard-interactive authentication fails.
     """
     packet = (NS('foo') + NS('none') + NS('keyboard-interactive')
             + NS('') + NS(''))
     response = '\x00\x00\x00\x02' + NS('bar') + NS('bar')
     d = self.authServer.ssh_USERAUTH_REQUEST(packet)
     self.authServer.ssh_USERAUTH_INFO_RESPONSE(response)
     def check(ignored):
         self.assertEqual(self.authServer.transport.packets[0],
                 (userauth.MSG_USERAUTH_INFO_REQUEST, (NS('') + NS('')
                     + NS('') + '\x00\x00\x00\x02' + NS('Name: ') + '\x01'
                     + NS('Password: '******'\x00')))
     return d.addCallback(check).addCallback(self._checkFailed)
Пример #28
0
 def test_failedPrivateKeyAuthenticationWithSignature(self):
     """
     Test that private key authentication fails when the public key
     is invalid.
     """
     blob = keys.Key.fromString(keydata.publicRSA_openssh).blob()
     obj = keys.Key.fromString(keydata.privateRSA_openssh)
     packet = (NS(b'foo') + NS(b'none') + NS(b'publickey') + b'\xff' +
               NS(b'ssh-rsa') + NS(blob) + NS(obj.sign(blob)))
     self.authServer.transport.sessionID = b'test'
     d = self.authServer.ssh_USERAUTH_REQUEST(packet)
     return d.addCallback(self._checkFailed)
Пример #29
0
    def ssh_SERVICE_REQUEST(self, packet):
        """
        Called when we get a MSG_SERVICE_REQUEST message.  Payload::
            string serviceName

        The client has requested a service.  If we can start the service,
        start it; otherwise, disconnect with
        DISCONNECT_SERVICE_NOT_AVAILABLE.
        """
        service, rest = getNS(packet)
        cls = self.factory.getService(self, service)
        if not cls:
            self.sendDisconnect(DISCONNECT_SERVICE_NOT_AVAILABLE,
                                "don't have service %s" % service)
            return
        else:
            self.sendPacket(MSG_SERVICE_ACCEPT, NS(service))
            self.setService(cls())
Пример #30
0
 def test_successfulPrivateKeyAuthentication(self):
     """
     Test that private key authentication completes successfully,
     """
     blob = keys.Key.fromString(keydata.publicRSA_openssh).blob()
     obj = keys.Key.fromString(keydata.privateRSA_openssh)
     packet = (NS('foo') + NS('none') + NS('publickey') + '\xff'
             + NS(obj.sshType()) + NS(blob))
     self.authServer.transport.sessionID = 'test'
     signature = obj.sign(NS('test') + chr(userauth.MSG_USERAUTH_REQUEST)
             + packet)
     packet += NS(signature)
     d = self.authServer.ssh_USERAUTH_REQUEST(packet)
     def check(ignored):
         self.assertEqual(self.authServer.transport.packets,
                 [(userauth.MSG_USERAUTH_SUCCESS, '')])
     return d.addCallback(check)