Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
transport.py3390 linesDownload Raw Back to paramiko
1# Copyright (C) 2003-2007  Robey Pointer <robeypointer@gmail.com>2# Copyright (C) 2003-2007  Robey Pointer <robeypointer@gmail.com>3#4# This file is part of paramiko.5#6# Paramiko is free software; you can redistribute it and/or modify it under the7# terms of the GNU Lesser General Public License as published by the Free8# Software Foundation; either version 2.1 of the License, or (at your option)9# any later version.10#11# Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY12# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR13# A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more14# details.15#16# You should have received a copy of the GNU Lesser General Public License17# along with Paramiko; if not, write to the Free Software Foundation, Inc.,18# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.19 20"""21Core protocol implementation22"""23 24import os25import socket26import sys27import threading28import time29import weakref30from hashlib import md5, sha1, sha256, sha51231 32from cryptography.hazmat.backends import default_backend33from cryptography.hazmat.primitives.ciphers import algorithms, Cipher, modes34 35import paramiko36from paramiko import util37from paramiko.auth_handler import AuthHandler, AuthOnlyHandler38from paramiko.ssh_gss import GSSAuth39from paramiko.channel import Channel40from paramiko.common import (41    xffffffff,42    cMSG_CHANNEL_OPEN,43    cMSG_IGNORE,44    cMSG_GLOBAL_REQUEST,45    DEBUG,46    MSG_KEXINIT,47    MSG_IGNORE,48    MSG_DISCONNECT,49    MSG_DEBUG,50    ERROR,51    WARNING,52    cMSG_UNIMPLEMENTED,53    INFO,54    cMSG_KEXINIT,55    cMSG_NEWKEYS,56    MSG_NEWKEYS,57    cMSG_REQUEST_SUCCESS,58    cMSG_REQUEST_FAILURE,59    CONNECTION_FAILED_CODE,60    OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED,61    OPEN_SUCCEEDED,62    cMSG_CHANNEL_OPEN_FAILURE,63    cMSG_CHANNEL_OPEN_SUCCESS,64    MSG_GLOBAL_REQUEST,65    MSG_REQUEST_SUCCESS,66    MSG_REQUEST_FAILURE,67    cMSG_SERVICE_REQUEST,68    MSG_SERVICE_ACCEPT,69    MSG_CHANNEL_OPEN_SUCCESS,70    MSG_CHANNEL_OPEN_FAILURE,71    MSG_CHANNEL_OPEN,72    MSG_CHANNEL_SUCCESS,73    MSG_CHANNEL_FAILURE,74    MSG_CHANNEL_DATA,75    MSG_CHANNEL_EXTENDED_DATA,76    MSG_CHANNEL_WINDOW_ADJUST,77    MSG_CHANNEL_REQUEST,78    MSG_CHANNEL_EOF,79    MSG_CHANNEL_CLOSE,80    MIN_WINDOW_SIZE,81    MIN_PACKET_SIZE,82    MAX_WINDOW_SIZE,83    DEFAULT_WINDOW_SIZE,84    DEFAULT_MAX_PACKET_SIZE,85    HIGHEST_USERAUTH_MESSAGE_ID,86    MSG_UNIMPLEMENTED,87    MSG_NAMES,88    MSG_EXT_INFO,89    cMSG_EXT_INFO,90    byte_ord,91)92from paramiko.compress import ZlibCompressor, ZlibDecompressor93from paramiko.dsskey import DSSKey94from paramiko.ed25519key import Ed25519Key95from paramiko.kex_curve25519 import KexCurve2551996from paramiko.kex_gex import KexGex, KexGexSHA25697from paramiko.kex_group1 import KexGroup198from paramiko.kex_group14 import KexGroup14, KexGroup14SHA25699from paramiko.kex_group16 import KexGroup16SHA512100from paramiko.kex_ecdh_nist import KexNistp256, KexNistp384, KexNistp521101from paramiko.kex_gss import KexGSSGex, KexGSSGroup1, KexGSSGroup14102from paramiko.message import Message103from paramiko.packet import Packetizer, NeedRekeyException104from paramiko.primes import ModulusPack105from paramiko.rsakey import RSAKey106from paramiko.ecdsakey import ECDSAKey107from paramiko.server import ServerInterface108from paramiko.sftp_client import SFTPClient109from paramiko.ssh_exception import (110    BadAuthenticationType,111    ChannelException,112    IncompatiblePeer,113    MessageOrderError,114    ProxyCommandFailure,115    SSHException,116)117from paramiko.util import (118    ClosingContextManager,119    clamp_value,120    b,121)122 123 124# for thread cleanup125_active_threads = []126 127 128def _join_lingering_threads():129    for thr in _active_threads:130        thr.stop_thread()131 132 133import atexit134 135atexit.register(_join_lingering_threads)136 137 138class Transport(threading.Thread, ClosingContextManager):139    """140    An SSH Transport attaches to a stream (usually a socket), negotiates an141    encrypted session, authenticates, and then creates stream tunnels, called142    `channels <.Channel>`, across the session.  Multiple channels can be143    multiplexed across a single session (and often are, in the case of port144    forwardings).145 146    Instances of this class may be used as context managers.147    """148 149    _ENCRYPT = object()150    _DECRYPT = object()151 152    _PROTO_ID = "2.0"153    _CLIENT_ID = "paramiko_{}".format(paramiko.__version__)154 155    # These tuples of algorithm identifiers are in preference order; do not156    # reorder without reason!157    # NOTE: if you need to modify these, we suggest leveraging the158    # `disabled_algorithms` constructor argument (also available in SSHClient)159    # instead of monkeypatching or subclassing.160    _preferred_ciphers = (161        "aes128-ctr",162        "aes192-ctr",163        "aes256-ctr",164        "aes128-cbc",165        "aes192-cbc",166        "aes256-cbc",167        "3des-cbc",168    )169    _preferred_macs = (170        "hmac-sha2-256",171        "hmac-sha2-512",172        "hmac-sha2-256-etm@openssh.com",173        "hmac-sha2-512-etm@openssh.com",174        "hmac-sha1",175        "hmac-md5",176        "hmac-sha1-96",177        "hmac-md5-96",178    )179    # ~= HostKeyAlgorithms in OpenSSH land180    _preferred_keys = (181        "ssh-ed25519",182        "ecdsa-sha2-nistp256",183        "ecdsa-sha2-nistp384",184        "ecdsa-sha2-nistp521",185        "rsa-sha2-512",186        "rsa-sha2-256",187        "ssh-rsa",188        "ssh-dss",189    )190    # ~= PubKeyAcceptedAlgorithms191    _preferred_pubkeys = (192        "ssh-ed25519",193        "ecdsa-sha2-nistp256",194        "ecdsa-sha2-nistp384",195        "ecdsa-sha2-nistp521",196        "rsa-sha2-512",197        "rsa-sha2-256",198        "ssh-rsa",199        "ssh-dss",200    )201    _preferred_kex = (202        "ecdh-sha2-nistp256",203        "ecdh-sha2-nistp384",204        "ecdh-sha2-nistp521",205        "diffie-hellman-group16-sha512",206        "diffie-hellman-group-exchange-sha256",207        "diffie-hellman-group14-sha256",208        "diffie-hellman-group-exchange-sha1",209        "diffie-hellman-group14-sha1",210        "diffie-hellman-group1-sha1",211    )212    if KexCurve25519.is_available():213        _preferred_kex = ("curve25519-sha256@libssh.org",) + _preferred_kex214    _preferred_gsskex = (215        "gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g==",216        "gss-group14-sha1-toWM5Slw5Ew8Mqkay+al2g==",217        "gss-group1-sha1-toWM5Slw5Ew8Mqkay+al2g==",218    )219    _preferred_compression = ("none",)220 221    _cipher_info = {222        "aes128-ctr": {223            "class": algorithms.AES,224            "mode": modes.CTR,225            "block-size": 16,226            "key-size": 16,227        },228        "aes192-ctr": {229            "class": algorithms.AES,230            "mode": modes.CTR,231            "block-size": 16,232            "key-size": 24,233        },234        "aes256-ctr": {235            "class": algorithms.AES,236            "mode": modes.CTR,237            "block-size": 16,238            "key-size": 32,239        },240        "aes128-cbc": {241            "class": algorithms.AES,242            "mode": modes.CBC,243            "block-size": 16,244            "key-size": 16,245        },246        "aes192-cbc": {247            "class": algorithms.AES,248            "mode": modes.CBC,249            "block-size": 16,250            "key-size": 24,251        },252        "aes256-cbc": {253            "class": algorithms.AES,254            "mode": modes.CBC,255            "block-size": 16,256            "key-size": 32,257        },258        "3des-cbc": {259            "class": algorithms.TripleDES,260            "mode": modes.CBC,261            "block-size": 8,262            "key-size": 24,263        },264    }265 266    _mac_info = {267        "hmac-sha1": {"class": sha1, "size": 20},268        "hmac-sha1-96": {"class": sha1, "size": 12},269        "hmac-sha2-256": {"class": sha256, "size": 32},270        "hmac-sha2-256-etm@openssh.com": {"class": sha256, "size": 32},271        "hmac-sha2-512": {"class": sha512, "size": 64},272        "hmac-sha2-512-etm@openssh.com": {"class": sha512, "size": 64},273        "hmac-md5": {"class": md5, "size": 16},274        "hmac-md5-96": {"class": md5, "size": 12},275    }276 277    _key_info = {278        # TODO: at some point we will want to drop this as it's no longer279        # considered secure due to using SHA-1 for signatures. OpenSSH 8.8 no280        # longer supports it. Question becomes at what point do we want to281        # prevent users with older setups from using this?282        "ssh-rsa": RSAKey,283        "ssh-rsa-cert-v01@openssh.com": RSAKey,284        "rsa-sha2-256": RSAKey,285        "rsa-sha2-256-cert-v01@openssh.com": RSAKey,286        "rsa-sha2-512": RSAKey,287        "rsa-sha2-512-cert-v01@openssh.com": RSAKey,288        "ssh-dss": DSSKey,289        "ssh-dss-cert-v01@openssh.com": DSSKey,290        "ecdsa-sha2-nistp256": ECDSAKey,291        "ecdsa-sha2-nistp256-cert-v01@openssh.com": ECDSAKey,292        "ecdsa-sha2-nistp384": ECDSAKey,293        "ecdsa-sha2-nistp384-cert-v01@openssh.com": ECDSAKey,294        "ecdsa-sha2-nistp521": ECDSAKey,295        "ecdsa-sha2-nistp521-cert-v01@openssh.com": ECDSAKey,296        "ssh-ed25519": Ed25519Key,297        "ssh-ed25519-cert-v01@openssh.com": Ed25519Key,298    }299 300    _kex_info = {301        "diffie-hellman-group1-sha1": KexGroup1,302        "diffie-hellman-group14-sha1": KexGroup14,303        "diffie-hellman-group-exchange-sha1": KexGex,304        "diffie-hellman-group-exchange-sha256": KexGexSHA256,305        "diffie-hellman-group14-sha256": KexGroup14SHA256,306        "diffie-hellman-group16-sha512": KexGroup16SHA512,307        "gss-group1-sha1-toWM5Slw5Ew8Mqkay+al2g==": KexGSSGroup1,308        "gss-group14-sha1-toWM5Slw5Ew8Mqkay+al2g==": KexGSSGroup14,309        "gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g==": KexGSSGex,310        "ecdh-sha2-nistp256": KexNistp256,311        "ecdh-sha2-nistp384": KexNistp384,312        "ecdh-sha2-nistp521": KexNistp521,313    }314    if KexCurve25519.is_available():315        _kex_info["curve25519-sha256@libssh.org"] = KexCurve25519316 317    _compression_info = {318        # zlib@openssh.com is just zlib, but only turned on after a successful319        # authentication.  openssh servers may only offer this type because320        # they've had troubles with security holes in zlib in the past.321        "zlib@openssh.com": (ZlibCompressor, ZlibDecompressor),322        "zlib": (ZlibCompressor, ZlibDecompressor),323        "none": (None, None),324    }325 326    _modulus_pack = None327    _active_check_timeout = 0.1328 329    def __init__(330        self,331        sock,332        default_window_size=DEFAULT_WINDOW_SIZE,333        default_max_packet_size=DEFAULT_MAX_PACKET_SIZE,334        gss_kex=False,335        gss_deleg_creds=True,336        disabled_algorithms=None,337        server_sig_algs=True,338        strict_kex=True,339        packetizer_class=None,340    ):341        """342        Create a new SSH session over an existing socket, or socket-like343        object.  This only creates the `.Transport` object; it doesn't begin344        the SSH session yet.  Use `connect` or `start_client` to begin a client345        session, or `start_server` to begin a server session.346 347        If the object is not actually a socket, it must have the following348        methods:349 350        - ``send(bytes)``: Writes from 1 to ``len(bytes)`` bytes, and returns351          an int representing the number of bytes written.  Returns352          0 or raises ``EOFError`` if the stream has been closed.353        - ``recv(int)``: Reads from 1 to ``int`` bytes and returns them as a354          string.  Returns 0 or raises ``EOFError`` if the stream has been355          closed.356        - ``close()``: Closes the socket.357        - ``settimeout(n)``: Sets a (float) timeout on I/O operations.358 359        For ease of use, you may also pass in an address (as a tuple) or a host360        string as the ``sock`` argument.  (A host string is a hostname with an361        optional port (separated by ``":"``) which will be converted into a362        tuple of ``(hostname, port)``.)  A socket will be connected to this363        address and used for communication.  Exceptions from the ``socket``364        call may be thrown in this case.365 366        .. note::367            Modifying the the window and packet sizes might have adverse368            effects on your channels created from this transport. The default369            values are the same as in the OpenSSH code base and have been370            battle tested.371 372        :param socket sock:373            a socket or socket-like object to create the session over.374        :param int default_window_size:375            sets the default window size on the transport. (defaults to376            2097152)377        :param int default_max_packet_size:378            sets the default max packet size on the transport. (defaults to379            32768)380        :param bool gss_kex:381            Whether to enable GSSAPI key exchange when GSSAPI is in play.382            Default: ``False``.383        :param bool gss_deleg_creds:384            Whether to enable GSSAPI credential delegation when GSSAPI is in385            play. Default: ``True``.386        :param dict disabled_algorithms:387            If given, must be a dictionary mapping algorithm type to an388            iterable of algorithm identifiers, which will be disabled for the389            lifetime of the transport.390 391            Keys should match the last word in the class' builtin algorithm392            tuple attributes, such as ``"ciphers"`` to disable names within393            ``_preferred_ciphers``; or ``"kex"`` to disable something defined394            inside ``_preferred_kex``. Values should exactly match members of395            the matching attribute.396 397            For example, if you need to disable398            ``diffie-hellman-group16-sha512`` key exchange (perhaps because399            your code talks to a server which implements it differently from400            Paramiko), specify ``disabled_algorithms={"kex":401            ["diffie-hellman-group16-sha512"]}``.402        :param bool server_sig_algs:403            Whether to send an extra message to compatible clients, in server404            mode, with a list of supported pubkey algorithms. Default:405            ``True``.406        :param bool strict_kex:407            Whether to advertise (and implement, if client also advertises408            support for) a "strict kex" mode for safer handshaking. Default:409            ``True``.410        :param packetizer_class:411            Which class to use for instantiating the internal packet handler.412            Default: ``None`` (i.e.: use `Packetizer` as normal).413 414        .. versionchanged:: 1.15415            Added the ``default_window_size`` and ``default_max_packet_size``416            arguments.417        .. versionchanged:: 1.15418            Added the ``gss_kex`` and ``gss_deleg_creds`` kwargs.419        .. versionchanged:: 2.6420            Added the ``disabled_algorithms`` kwarg.421        .. versionchanged:: 2.9422            Added the ``server_sig_algs`` kwarg.423        .. versionchanged:: 3.4424            Added the ``strict_kex`` kwarg.425        .. versionchanged:: 3.4426            Added the ``packetizer_class`` kwarg.427        """428        self.active = False429        self.hostname = None430        self.server_extensions = {}431        self.advertise_strict_kex = strict_kex432        self.agreed_on_strict_kex = False433 434        # TODO: these two overrides on sock's type should go away sometime, too435        # many ways to do it!436        if isinstance(sock, str):437            # convert "host:port" into (host, port)438            hl = sock.split(":", 1)439            self.hostname = hl[0]440            if len(hl) == 1:441                sock = (hl[0], 22)442            else:443                sock = (hl[0], int(hl[1]))444        if type(sock) is tuple:445            # connect to the given (host, port)446            hostname, port = sock447            self.hostname = hostname448            reason = "No suitable address family"449            addrinfos = socket.getaddrinfo(450                hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM451            )452            for family, socktype, proto, canonname, sockaddr in addrinfos:453                if socktype == socket.SOCK_STREAM:454                    af = family455                    # addr = sockaddr456                    sock = socket.socket(af, socket.SOCK_STREAM)457                    try:458                        sock.connect((hostname, port))459                    except socket.error as e:460                        reason = str(e)461                    else:462                        break463            else:464                raise SSHException(465                    "Unable to connect to {}: {}".format(hostname, reason)466                )467        # okay, normal socket-ish flow here...468        threading.Thread.__init__(self)469        self.daemon = True470        self.sock = sock471        # we set the timeout so we can check self.active periodically to472        # see if we should bail. socket.timeout exception is never propagated.473        self.sock.settimeout(self._active_check_timeout)474 475        # negotiated crypto parameters476        self.packetizer = (packetizer_class or Packetizer)(sock)477        self.local_version = "SSH-" + self._PROTO_ID + "-" + self._CLIENT_ID478        self.remote_version = ""479        self.local_cipher = self.remote_cipher = ""480        self.local_kex_init = self.remote_kex_init = None481        self.local_mac = self.remote_mac = None482        self.local_compression = self.remote_compression = None483        self.session_id = None484        self.host_key_type = None485        self.host_key = None486 487        # GSS-API / SSPI Key Exchange488        self.use_gss_kex = gss_kex489        # This will be set to True if GSS-API Key Exchange was performed490        self.gss_kex_used = False491        self.kexgss_ctxt = None492        self.gss_host = None493        if self.use_gss_kex:494            self.kexgss_ctxt = GSSAuth("gssapi-keyex", gss_deleg_creds)495            self._preferred_kex = self._preferred_gsskex + self._preferred_kex496 497        # state used during negotiation498        self.kex_engine = None499        self.H = None500        self.K = None501 502        self.initial_kex_done = False503        self.in_kex = False504        self.authenticated = False505        self._expected_packet = tuple()506        # synchronization (always higher level than write_lock)507        self.lock = threading.Lock()508 509        # tracking open channels510        self._channels = ChannelMap()511        self.channel_events = {}  # (id -> Event)512        self.channels_seen = {}  # (id -> True)513        self._channel_counter = 0514        self.default_max_packet_size = default_max_packet_size515        self.default_window_size = default_window_size516        self._forward_agent_handler = None517        self._x11_handler = None518        self._tcp_handler = None519 520        self.saved_exception = None521        self.clear_to_send = threading.Event()522        self.clear_to_send_lock = threading.Lock()523        self.clear_to_send_timeout = 30.0524        self.log_name = "paramiko.transport"525        self.logger = util.get_logger(self.log_name)526        self.packetizer.set_log(self.logger)527        self.auth_handler = None528        # response Message from an arbitrary global request529        self.global_response = None530        # user-defined event callbacks531        self.completion_event = None532        # how long (seconds) to wait for the SSH banner533        self.banner_timeout = 15534        # how long (seconds) to wait for the handshake to finish after SSH535        # banner sent.536        self.handshake_timeout = 15537        # how long (seconds) to wait for the auth response.538        self.auth_timeout = 30539        # how long (seconds) to wait for opening a channel540        self.channel_timeout = 60 * 60541        self.disabled_algorithms = disabled_algorithms or {}542        self.server_sig_algs = server_sig_algs543 544        # server mode:545        self.server_mode = False546        self.server_object = None547        self.server_key_dict = {}548        self.server_accepts = []549        self.server_accept_cv = threading.Condition(self.lock)550        self.subsystem_table = {}551 552        # Handler table, now set at init time for easier per-instance553        # manipulation and subclass twiddling.554        self._handler_table = {555            MSG_EXT_INFO: self._parse_ext_info,556            MSG_NEWKEYS: self._parse_newkeys,557            MSG_GLOBAL_REQUEST: self._parse_global_request,558            MSG_REQUEST_SUCCESS: self._parse_request_success,559            MSG_REQUEST_FAILURE: self._parse_request_failure,560            MSG_CHANNEL_OPEN_SUCCESS: self._parse_channel_open_success,561            MSG_CHANNEL_OPEN_FAILURE: self._parse_channel_open_failure,562            MSG_CHANNEL_OPEN: self._parse_channel_open,563            MSG_KEXINIT: self._negotiate_keys,564        }565 566    def _filter_algorithm(self, type_):567        default = getattr(self, "_preferred_{}".format(type_))568        return tuple(569            x570            for x in default571            if x not in self.disabled_algorithms.get(type_, [])572        )573 574    @property575    def preferred_ciphers(self):576        return self._filter_algorithm("ciphers")577 578    @property579    def preferred_macs(self):580        return self._filter_algorithm("macs")581 582    @property583    def preferred_keys(self):584        # Interleave cert variants here; resistant to various background585        # overwriting of _preferred_keys, and necessary as hostkeys can't use586        # the logic pubkey auth does re: injecting/checking for certs at587        # runtime588        filtered = self._filter_algorithm("keys")589        return tuple(590            filtered591            + tuple("{}-cert-v01@openssh.com".format(x) for x in filtered)592        )593 594    @property595    def preferred_pubkeys(self):596        return self._filter_algorithm("pubkeys")597 598    @property599    def preferred_kex(self):600        return self._filter_algorithm("kex")601 602    @property603    def preferred_compression(self):604        return self._filter_algorithm("compression")605 606    def __repr__(self):607        """608        Returns a string representation of this object, for debugging.609        """610        id_ = hex(id(self) & xffffffff)611        out = "<paramiko.Transport at {}".format(id_)612        if not self.active:613            out += " (unconnected)"614        else:615            if self.local_cipher != "":616                out += " (cipher {}, {:d} bits)".format(617                    self.local_cipher,618                    self._cipher_info[self.local_cipher]["key-size"] * 8,619                )620            if self.is_authenticated():621                out += " (active; {} open channel(s))".format(622                    len(self._channels)623                )624            elif self.initial_kex_done:625                out += " (connected; awaiting auth)"626            else:627                out += " (connecting)"628        out += ">"629        return out630 631    def atfork(self):632        """633        Terminate this Transport without closing the session.  On posix634        systems, if a Transport is open during process forking, both parent635        and child will share the underlying socket, but only one process can636        use the connection (without corrupting the session).  Use this method637        to clean up a Transport object without disrupting the other process.638 639        .. versionadded:: 1.5.3640        """641        self.sock.close()642        self.close()643 644    def get_security_options(self):645        """646        Return a `.SecurityOptions` object which can be used to tweak the647        encryption algorithms this transport will permit (for encryption,648        digest/hash operations, public keys, and key exchanges) and the order649        of preference for them.650        """651        return SecurityOptions(self)652 653    def set_gss_host(self, gss_host, trust_dns=True, gssapi_requested=True):654        """655        Normalize/canonicalize ``self.gss_host`` depending on various factors.656 657        :param str gss_host:658            The explicitly requested GSS-oriented hostname to connect to (i.e.659            what the host's name is in the Kerberos database.) Defaults to660            ``self.hostname`` (which will be the 'real' target hostname and/or661            host portion of given socket object.)662        :param bool trust_dns:663            Indicates whether or not DNS is trusted; if true, DNS will be used664            to canonicalize the GSS hostname (which again will either be665            ``gss_host`` or the transport's default hostname.)666            (Defaults to True due to backwards compatibility.)667        :param bool gssapi_requested:668            Whether GSSAPI key exchange or authentication was even requested.669            If not, this is a no-op and nothing happens670            (and ``self.gss_host`` is not set.)671            (Defaults to True due to backwards compatibility.)672        :returns: ``None``.673        """674        # No GSSAPI in play == nothing to do675        if not gssapi_requested:676            return677        # Obtain the correct host first - did user request a GSS-specific name678        # to use that is distinct from the actual SSH target hostname?679        if gss_host is None:680            gss_host = self.hostname681        # Finally, canonicalize via DNS if DNS is trusted.682        if trust_dns and gss_host is not None:683            gss_host = socket.getfqdn(gss_host)684        # And set attribute for reference later.685        self.gss_host = gss_host686 687    def start_client(self, event=None, timeout=None):688        """689        Negotiate a new SSH2 session as a client.  This is the first step after690        creating a new `.Transport`.  A separate thread is created for protocol691        negotiation.692 693        If an event is passed in, this method returns immediately.  When694        negotiation is done (successful or not), the given ``Event`` will695        be triggered.  On failure, `is_active` will return ``False``.696 697        (Since 1.4) If ``event`` is ``None``, this method will not return until698        negotiation is done.  On success, the method returns normally.699        Otherwise an SSHException is raised.700 701        After a successful negotiation, you will usually want to authenticate,702        calling `auth_password <Transport.auth_password>` or703        `auth_publickey <Transport.auth_publickey>`.704 705        .. note:: `connect` is a simpler method for connecting as a client.706 707        .. note::708            After calling this method (or `start_server` or `connect`), you709            should no longer directly read from or write to the original socket710            object.711 712        :param .threading.Event event:713            an event to trigger when negotiation is complete (optional)714 715        :param float timeout:716            a timeout, in seconds, for SSH2 session negotiation (optional)717 718        :raises:719            `.SSHException` -- if negotiation fails (and no ``event`` was720            passed in)721        """722        self.active = True723        if event is not None:724            # async, return immediately and let the app poll for completion725            self.completion_event = event726            self.start()727            return728 729        # synchronous, wait for a result730        self.completion_event = event = threading.Event()731        self.start()732        max_time = time.time() + timeout if timeout is not None else None733        while True:734            event.wait(0.1)735            if not self.active:736                e = self.get_exception()737                if e is not None:738                    raise e739                raise SSHException("Negotiation failed.")740            if event.is_set() or (741                timeout is not None and time.time() >= max_time742            ):743                break744 745    def start_server(self, event=None, server=None):746        """747        Negotiate a new SSH2 session as a server.  This is the first step after748        creating a new `.Transport` and setting up your server host key(s).  A749        separate thread is created for protocol negotiation.750 751        If an event is passed in, this method returns immediately.  When752        negotiation is done (successful or not), the given ``Event`` will753        be triggered.  On failure, `is_active` will return ``False``.754 755        (Since 1.4) If ``event`` is ``None``, this method will not return until756        negotiation is done.  On success, the method returns normally.757        Otherwise an SSHException is raised.758 759        After a successful negotiation, the client will need to authenticate.760        Override the methods `get_allowed_auths761        <.ServerInterface.get_allowed_auths>`, `check_auth_none762        <.ServerInterface.check_auth_none>`, `check_auth_password763        <.ServerInterface.check_auth_password>`, and `check_auth_publickey764        <.ServerInterface.check_auth_publickey>` in the given ``server`` object765        to control the authentication process.766 767        After a successful authentication, the client should request to open a768        channel.  Override `check_channel_request769        <.ServerInterface.check_channel_request>` in the given ``server``770        object to allow channels to be opened.771 772        .. note::773            After calling this method (or `start_client` or `connect`), you774            should no longer directly read from or write to the original socket775            object.776 777        :param .threading.Event event:778            an event to trigger when negotiation is complete.779        :param .ServerInterface server:780            an object used to perform authentication and create `channels781            <.Channel>`782 783        :raises:784            `.SSHException` -- if negotiation fails (and no ``event`` was785            passed in)786        """787        if server is None:788            server = ServerInterface()789        self.server_mode = True790        self.server_object = server791        self.active = True792        if event is not None:793            # async, return immediately and let the app poll for completion794            self.completion_event = event795            self.start()796            return797 798        # synchronous, wait for a result799        self.completion_event = event = threading.Event()800        self.start()801        while True:802            event.wait(0.1)803            if not self.active:804                e = self.get_exception()805                if e is not None:806                    raise e807                raise SSHException("Negotiation failed.")808            if event.is_set():809                break810 811    def add_server_key(self, key):812        """813        Add a host key to the list of keys used for server mode.  When behaving814        as a server, the host key is used to sign certain packets during the815        SSH2 negotiation, so that the client can trust that we are who we say816        we are.  Because this is used for signing, the key must contain private817        key info, not just the public half.  Only one key of each type (RSA or818        DSS) is kept.819 820        :param .PKey key:821            the host key to add, usually an `.RSAKey` or `.DSSKey`.822        """823        self.server_key_dict[key.get_name()] = key824        # Handle SHA-2 extensions for RSA by ensuring that lookups into825        # self.server_key_dict will yield this key for any of the algorithm826        # names.827        if isinstance(key, RSAKey):828            self.server_key_dict["rsa-sha2-256"] = key829            self.server_key_dict["rsa-sha2-512"] = key830 831    def get_server_key(self):832        """833        Return the active host key, in server mode.  After negotiating with the834        client, this method will return the negotiated host key.  If only one835        type of host key was set with `add_server_key`, that's the only key836        that will ever be returned.  But in cases where you have set more than837        one type of host key (for example, an RSA key and a DSS key), the key838        type will be negotiated by the client, and this method will return the839        key of the type agreed on.  If the host key has not been negotiated840        yet, ``None`` is returned.  In client mode, the behavior is undefined.841 842        :return:843            host key (`.PKey`) of the type negotiated by the client, or844            ``None``.845        """846        try:847            return self.server_key_dict[self.host_key_type]848        except KeyError:849            pass850        return None851 852    @staticmethod853    def load_server_moduli(filename=None):854        """855        (optional)856        Load a file of prime moduli for use in doing group-exchange key857        negotiation in server mode.  It's a rather obscure option and can be858        safely ignored.859 860        In server mode, the remote client may request "group-exchange" key861        negotiation, which asks the server to send a random prime number that862        fits certain criteria.  These primes are pretty difficult to compute,863        so they can't be generated on demand.  But many systems contain a file864        of suitable primes (usually named something like ``/etc/ssh/moduli``).865        If you call `load_server_moduli` and it returns ``True``, then this866        file of primes has been loaded and we will support "group-exchange" in867        server mode.  Otherwise server mode will just claim that it doesn't868        support that method of key negotiation.869 870        :param str filename:871            optional path to the moduli file, if you happen to know that it's872            not in a standard location.873        :return:874            True if a moduli file was successfully loaded; False otherwise.875 876        .. note:: This has no effect when used in client mode.877        """878        Transport._modulus_pack = ModulusPack()879        # places to look for the openssh "moduli" file880        file_list = ["/etc/ssh/moduli", "/usr/local/etc/moduli"]881        if filename is not None:882            file_list.insert(0, filename)883        for fn in file_list:884            try:885                Transport._modulus_pack.read_file(fn)886                return True887            except IOError:888                pass889        # none succeeded890        Transport._modulus_pack = None891        return False892 893    def close(self):894        """895        Close this session, and any open channels that are tied to it.896        """897        if not self.active:898            return899        self.stop_thread()900        for chan in list(self._channels.values()):901            chan._unlink()902        self.sock.close()903 904    def get_remote_server_key(self):905        """906        Return the host key of the server (in client mode).907 908        .. note::909            Previously this call returned a tuple of ``(key type, key910            string)``. You can get the same effect by calling `.PKey.get_name`911            for the key type, and ``str(key)`` for the key string.912 913        :raises: `.SSHException` -- if no session is currently active.914 915        :return: public key (`.PKey`) of the remote server916        """917        if (not self.active) or (not self.initial_kex_done):918            raise SSHException("No existing session")919        return self.host_key920 921    def is_active(self):922        """923        Return true if this session is active (open).924 925        :return:926            True if the session is still active (open); False if the session is927            closed928        """929        return self.active930 931    def open_session(932        self, window_size=None, max_packet_size=None, timeout=None933    ):934        """935        Request a new channel to the server, of type ``"session"``.  This is936        just an alias for calling `open_channel` with an argument of937        ``"session"``.938 939        .. note:: Modifying the the window and packet sizes might have adverse940            effects on the session created. The default values are the same941            as in the OpenSSH code base and have been battle tested.942 943        :param int window_size:944            optional window size for this session.945        :param int max_packet_size:946            optional max packet size for this session.947 948        :return: a new `.Channel`949 950        :raises:951            `.SSHException` -- if the request is rejected or the session ends952            prematurely953 954        .. versionchanged:: 1.13.4/1.14.3/1.15.3955            Added the ``timeout`` argument.956        .. versionchanged:: 1.15957            Added the ``window_size`` and ``max_packet_size`` arguments.958        """959        return self.open_channel(960            "session",961            window_size=window_size,962            max_packet_size=max_packet_size,963            timeout=timeout,964        )965 966    def open_x11_channel(self, src_addr=None):967        """968        Request a new channel to the client, of type ``"x11"``.  This969        is just an alias for ``open_channel('x11', src_addr=src_addr)``.970 971        :param tuple src_addr:972            the source address (``(str, int)``) of the x11 server (port is the973            x11 port, ie. 6010)974        :return: a new `.Channel`975 976        :raises:977            `.SSHException` -- if the request is rejected or the session ends978            prematurely979        """980        return self.open_channel("x11", src_addr=src_addr)981 982    def open_forward_agent_channel(self):983        """984        Request a new channel to the client, of type985        ``"auth-agent@openssh.com"``.986 987        This is just an alias for ``open_channel('auth-agent@openssh.com')``.988 989        :return: a new `.Channel`990 991        :raises: `.SSHException` --992            if the request is rejected or the session ends prematurely993        """994        return self.open_channel("auth-agent@openssh.com")995 996    def open_forwarded_tcpip_channel(self, src_addr, dest_addr):997        """998        Request a new channel back to the client, of type ``forwarded-tcpip``.999 1000        This is used after a client has requested port forwarding, for sending1001        incoming connections back to the client.1002 1003        :param src_addr: originator's address1004        :param dest_addr: local (server) connected address1005        """1006        return self.open_channel("forwarded-tcpip", dest_addr, src_addr)1007 1008    def open_channel(1009        self,1010        kind,1011        dest_addr=None,1012        src_addr=None,1013        window_size=None,1014        max_packet_size=None,1015        timeout=None,1016    ):1017        """1018        Request a new channel to the server. `Channels <.Channel>` are1019        socket-like objects used for the actual transfer of data across the1020        session. You may only request a channel after negotiating encryption1021        (using `connect` or `start_client`) and authenticating.1022 1023        .. note:: Modifying the the window and packet sizes might have adverse1024            effects on the channel created. The default values are the same1025            as in the OpenSSH code base and have been battle tested.1026 1027        :param str kind:1028            the kind of channel requested (usually ``"session"``,1029            ``"forwarded-tcpip"``, ``"direct-tcpip"``, or ``"x11"``)1030        :param tuple dest_addr:1031            the destination address (address + port tuple) of this port1032            forwarding, if ``kind`` is ``"forwarded-tcpip"`` or1033            ``"direct-tcpip"`` (ignored for other channel types)1034        :param src_addr: the source address of this port forwarding, if1035            ``kind`` is ``"forwarded-tcpip"``, ``"direct-tcpip"``, or ``"x11"``1036        :param int window_size:1037            optional window size for this session.1038        :param int max_packet_size:1039            optional max packet size for this session.1040        :param float timeout:1041            optional timeout opening a channel, default 3600s (1h)1042 1043        :return: a new `.Channel` on success1044 1045        :raises:1046            `.SSHException` -- if the request is rejected, the session ends1047            prematurely or there is a timeout opening a channel1048 1049        .. versionchanged:: 1.151050            Added the ``window_size`` and ``max_packet_size`` arguments.1051        """1052        if not self.active:1053            raise SSHException("SSH session not active")1054        timeout = self.channel_timeout if timeout is None else timeout1055        self.lock.acquire()1056        try:1057            window_size = self._sanitize_window_size(window_size)1058            max_packet_size = self._sanitize_packet_size(max_packet_size)1059            chanid = self._next_channel()1060            m = Message()1061            m.add_byte(cMSG_CHANNEL_OPEN)1062            m.add_string(kind)1063            m.add_int(chanid)1064            m.add_int(window_size)1065            m.add_int(max_packet_size)1066            if (kind == "forwarded-tcpip") or (kind == "direct-tcpip"):1067                m.add_string(dest_addr[0])1068                m.add_int(dest_addr[1])1069                m.add_string(src_addr[0])1070                m.add_int(src_addr[1])1071            elif kind == "x11":1072                m.add_string(src_addr[0])1073                m.add_int(src_addr[1])1074            chan = Channel(chanid)1075            self._channels.put(chanid, chan)1076            self.channel_events[chanid] = event = threading.Event()1077            self.channels_seen[chanid] = True1078            chan._set_transport(self)1079            chan._set_window(window_size, max_packet_size)1080        finally:1081            self.lock.release()1082        self._send_user_message(m)1083        start_ts = time.time()1084        while True:1085            event.wait(0.1)1086            if not self.active:1087                e = self.get_exception()1088                if e is None:1089                    e = SSHException("Unable to open channel.")1090                raise e1091            if event.is_set():1092                break1093            elif start_ts + timeout < time.time():1094                raise SSHException("Timeout opening channel.")1095        chan = self._channels.get(chanid)1096        if chan is not None:1097            return chan1098        e = self.get_exception()1099        if e is None:1100            e = SSHException("Unable to open channel.")1101        raise e1102 1103    def request_port_forward(self, address, port, handler=None):1104        """1105        Ask the server to forward TCP connections from a listening port on1106        the server, across this SSH session.1107 1108        If a handler is given, that handler is called from a different thread1109        whenever a forwarded connection arrives.  The handler parameters are::1110 1111            handler(1112                channel,1113                (origin_addr, origin_port),1114                (server_addr, server_port),1115            )1116 1117        where ``server_addr`` and ``server_port`` are the address and port that1118        the server was listening on.1119 1120        If no handler is set, the default behavior is to send new incoming1121        forwarded connections into the accept queue, to be picked up via1122        `accept`.1123 1124        :param str address: the address to bind when forwarding1125        :param int port:1126            the port to forward, or 0 to ask the server to allocate any port1127        :param callable handler:1128            optional handler for incoming forwarded connections, of the form1129            ``func(Channel, (str, int), (str, int))``.1130 1131        :return: the port number (`int`) allocated by the server1132 1133        :raises:1134            `.SSHException` -- if the server refused the TCP forward request1135        """1136        if not self.active:1137            raise SSHException("SSH session not active")1138        port = int(port)1139        response = self.global_request(1140            "tcpip-forward", (address, port), wait=True1141        )1142        if response is None:1143            raise SSHException("TCP forwarding request denied")1144        if port == 0:1145            port = response.get_int()1146        if handler is None:1147 1148            def default_handler(channel, src_addr, dest_addr_port):1149                # src_addr, src_port = src_addr_port1150                # dest_addr, dest_port = dest_addr_port1151                self._queue_incoming_channel(channel)1152 1153            handler = default_handler1154        self._tcp_handler = handler1155        return port1156 1157    def cancel_port_forward(self, address, port):1158        """1159        Ask the server to cancel a previous port-forwarding request.  No more1160        connections to the given address & port will be forwarded across this1161        ssh connection.1162 1163        :param str address: the address to stop forwarding1164        :param int port: the port to stop forwarding1165        """1166        if not self.active:1167            return1168        self._tcp_handler = None1169        self.global_request("cancel-tcpip-forward", (address, port), wait=True)1170 1171    def open_sftp_client(self):1172        """1173        Create an SFTP client channel from an open transport.  On success, an1174        SFTP session will be opened with the remote host, and a new1175        `.SFTPClient` object will be returned.1176 1177        :return:1178            a new `.SFTPClient` referring to an sftp session (channel) across1179            this transport1180        """1181        return SFTPClient.from_transport(self)1182 1183    def send_ignore(self, byte_count=None):1184        """1185        Send a junk packet across the encrypted link.  This is sometimes used1186        to add "noise" to a connection to confuse would-be attackers.  It can1187        also be used as a keep-alive for long lived connections traversing1188        firewalls.1189 1190        :param int byte_count:1191            the number of random bytes to send in the payload of the ignored1192            packet -- defaults to a random number from 10 to 41.1193        """1194        m = Message()1195        m.add_byte(cMSG_IGNORE)1196        if byte_count is None:1197            byte_count = (byte_ord(os.urandom(1)) % 32) + 101198        m.add_bytes(os.urandom(byte_count))1199        self._send_user_message(m)1200 

Showing the first 1,200 of 3390 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai