Statistics
| Branch: | Tag: | Revision:

root / ncclient / ssh.py @ 2acc860a

History | View | Annotate | Download (5.3 kB)

1 589b23e4 Shikhar Bhushan
# Copyright 2009 Shikhar Bhushan
2 589b23e4 Shikhar Bhushan
#
3 589b23e4 Shikhar Bhushan
# Licensed under the Apache License, Version 2.0 (the "License");
4 589b23e4 Shikhar Bhushan
# you may not use this file except in compliance with the License.
5 589b23e4 Shikhar Bhushan
# You may obtain a copy of the License at
6 589b23e4 Shikhar Bhushan
#
7 589b23e4 Shikhar Bhushan
#    http://www.apache.org/licenses/LICENSE-2.0
8 589b23e4 Shikhar Bhushan
#
9 589b23e4 Shikhar Bhushan
# Unless required by applicable law or agreed to in writing, software
10 589b23e4 Shikhar Bhushan
# distributed under the License is distributed on an "AS IS" BASIS,
11 589b23e4 Shikhar Bhushan
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 589b23e4 Shikhar Bhushan
# See the License for the specific language governing permissions and
13 589b23e4 Shikhar Bhushan
# limitations under the License.
14 589b23e4 Shikhar Bhushan
15 589b23e4 Shikhar Bhushan
import logging
16 927205da Shikhar Bhushan
from cStringIO import StringIO
17 ee4bb099 Shikhar Bhushan
from os import SEEK_CUR
18 2acc860a Shikhar Bhushan
import socket
19 ee4bb099 Shikhar Bhushan
20 ee4bb099 Shikhar Bhushan
import paramiko
21 927205da Shikhar Bhushan
22 2acc860a Shikhar Bhushan
23 589b23e4 Shikhar Bhushan
from session import Session, SessionError
24 589b23e4 Shikhar Bhushan
25 589b23e4 Shikhar Bhushan
logger = logging.getLogger('ncclient.ssh')
26 589b23e4 Shikhar Bhushan
27 927205da Shikhar Bhushan
28 589b23e4 Shikhar Bhushan
class SessionCloseError(SessionError):
29 589b23e4 Shikhar Bhushan
    
30 589b23e4 Shikhar Bhushan
    def __str__(self):
31 589b23e4 Shikhar Bhushan
        return 'RECEIVED: %s | UNSENT: %s' % (self._in_buf, self._out_buf)
32 589b23e4 Shikhar Bhushan
    
33 38a9b062 Shikhar Bhushan
    def __init__(self, in_buf, out_buf=None):
34 589b23e4 Shikhar Bhushan
        SessionError.__init__(self)
35 589b23e4 Shikhar Bhushan
        self._in_buf, self._out_buf = in_buf, out_buf
36 589b23e4 Shikhar Bhushan
37 927205da Shikhar Bhushan
38 589b23e4 Shikhar Bhushan
class SSHSession(Session):
39 589b23e4 Shikhar Bhushan
40 589b23e4 Shikhar Bhushan
    BUF_SIZE = 4096
41 38a9b062 Shikhar Bhushan
    MSG_DELIM = ']]>]]>'
42 589b23e4 Shikhar Bhushan
    
43 589b23e4 Shikhar Bhushan
    def __init__(self, load_known_hosts=True,
44 2acc860a Shikhar Bhushan
                 missing_host_key_policy=paramiko.RejectPolicy()):
45 589b23e4 Shikhar Bhushan
        Session.__init__(self)
46 589b23e4 Shikhar Bhushan
        self._client = paramiko.SSHClient()
47 ee4bb099 Shikhar Bhushan
        self._channel = None
48 589b23e4 Shikhar Bhushan
        if load_known_hosts:
49 589b23e4 Shikhar Bhushan
            self._client.load_system_host_keys()
50 589b23e4 Shikhar Bhushan
        self._client.set_missing_host_key_policy(missing_host_key_policy)
51 927205da Shikhar Bhushan
        self._in_buf = StringIO()
52 38a9b062 Shikhar Bhushan
        self._parsing_state = 0
53 927205da Shikhar Bhushan
        self._parsing_pos = 0
54 927205da Shikhar Bhushan
    
55 ee4bb099 Shikhar Bhushan
    def _close(self):
56 ee4bb099 Shikhar Bhushan
        self._channel.close()
57 ee4bb099 Shikhar Bhushan
        self._connected = False
58 ee4bb099 Shikhar Bhushan
    
59 ee4bb099 Shikhar Bhushan
    def _fresh_data(self):
60 ee4bb099 Shikhar Bhushan
        delim = SSHSession.MSG_DELIM
61 ee4bb099 Shikhar Bhushan
        n = len(delim) - 1
62 ee4bb099 Shikhar Bhushan
        state = self._parsing_state
63 ee4bb099 Shikhar Bhushan
        buf = self._in_buf
64 ee4bb099 Shikhar Bhushan
        buf.seek(self._parsing_pos)
65 ee4bb099 Shikhar Bhushan
        while True:
66 ee4bb099 Shikhar Bhushan
            x = buf.read(1)
67 ee4bb099 Shikhar Bhushan
            if not x: # done reading
68 ee4bb099 Shikhar Bhushan
                break
69 ee4bb099 Shikhar Bhushan
            elif x == delim[state]:
70 ee4bb099 Shikhar Bhushan
                state += 1
71 ee4bb099 Shikhar Bhushan
            else:
72 ee4bb099 Shikhar Bhushan
                continue
73 ee4bb099 Shikhar Bhushan
            # loop till last delim char expected, break if other char encountered
74 ee4bb099 Shikhar Bhushan
            for i in range(state, n):
75 ee4bb099 Shikhar Bhushan
                x = buf.read(1)
76 ee4bb099 Shikhar Bhushan
                if not x: # done reading
77 ee4bb099 Shikhar Bhushan
                    break
78 ee4bb099 Shikhar Bhushan
                if x==delim[i]: # what we expected
79 ee4bb099 Shikhar Bhushan
                    state += 1 # expect the next delim char
80 ee4bb099 Shikhar Bhushan
                else:
81 ee4bb099 Shikhar Bhushan
                    state = 0 # reset
82 ee4bb099 Shikhar Bhushan
                    break
83 ee4bb099 Shikhar Bhushan
            else: # if we didn't break out of above loop, full delim parsed
84 ee4bb099 Shikhar Bhushan
                till = buf.tell() - n
85 ee4bb099 Shikhar Bhushan
                buf.seek(0)
86 ee4bb099 Shikhar Bhushan
                msg = buf.read(till)
87 ee4bb099 Shikhar Bhushan
                self.dispatch('reply', msg)
88 ee4bb099 Shikhar Bhushan
                buf.seek(n+1, SEEK_CUR)
89 ee4bb099 Shikhar Bhushan
                rest = buf.read()
90 ee4bb099 Shikhar Bhushan
                buf = StringIO()
91 ee4bb099 Shikhar Bhushan
                buf.write(rest)
92 ee4bb099 Shikhar Bhushan
                buf.seek(0)
93 ee4bb099 Shikhar Bhushan
                state = 0
94 ee4bb099 Shikhar Bhushan
        self._in_buf = buf
95 ee4bb099 Shikhar Bhushan
        self._parsing_state = state
96 ee4bb099 Shikhar Bhushan
        self._parsing_pos = self._in_buf.tell()
97 ee4bb099 Shikhar Bhushan
98 2acc860a Shikhar Bhushan
    #def load_host_keys(self, filename):
99 2acc860a Shikhar Bhushan
    #    self._client.load_host_keys(filename)
100 2acc860a Shikhar Bhushan
    #
101 2acc860a Shikhar Bhushan
    #def set_missing_host_key_policy(self, policy):
102 2acc860a Shikhar Bhushan
    #    self._client.set_missing_host_key_policy(policy)
103 2acc860a Shikhar Bhushan
    #
104 2acc860a Shikhar Bhushan
    #def connect(self, hostname, port=830, username=None, password=None,
105 2acc860a Shikhar Bhushan
    #            key_filename=None, timeout=None, allow_agent=True,
106 2acc860a Shikhar Bhushan
    #            look_for_keys=True):
107 2acc860a Shikhar Bhushan
    #    self._client.connect(hostname, port=port, username=username,
108 2acc860a Shikhar Bhushan
    #                        password=password, key_filename=key_filename,
109 2acc860a Shikhar Bhushan
    #                        timeout=timeout, allow_agent=allow_agent,
110 2acc860a Shikhar Bhushan
    #                        look_for_keys=look_for_keys)    
111 2acc860a Shikhar Bhushan
    #    transport = self._client.get_transport()
112 2acc860a Shikhar Bhushan
    #    self._channel = transport.open_session()
113 2acc860a Shikhar Bhushan
    #    self._channel.invoke_subsystem('netconf')
114 2acc860a Shikhar Bhushan
    #    self._channel.set_name('netconf')
115 2acc860a Shikhar Bhushan
    #    self._connected = True
116 2acc860a Shikhar Bhushan
    #    self._post_connect()
117 2acc860a Shikhar Bhushan
118 589b23e4 Shikhar Bhushan
    def connect(self, hostname, port=830, username=None, password=None,
119 589b23e4 Shikhar Bhushan
                key_filename=None, timeout=None, allow_agent=True,
120 589b23e4 Shikhar Bhushan
                look_for_keys=True):
121 2acc860a Shikhar Bhushan
        self._transport = paramiko.Transport()
122 927205da Shikhar Bhushan
    
123 589b23e4 Shikhar Bhushan
    def run(self):
124 589b23e4 Shikhar Bhushan
        chan = self._channel
125 589b23e4 Shikhar Bhushan
        chan.setblocking(0)
126 589b23e4 Shikhar Bhushan
        q = self._q
127 0fd74489 Shikhar Bhushan
        try:
128 38a9b062 Shikhar Bhushan
            while True:    
129 0fd74489 Shikhar Bhushan
                if chan.closed:
130 38a9b062 Shikhar Bhushan
                    raise SessionCloseError(self._in_buf.getvalue())         
131 38a9b062 Shikhar Bhushan
                if chan.send_ready() and not q.empty():
132 3ad93428 Shikhar Bhushan
                    data = q.get() + SSHSession.MSG_DELIM
133 0fd74489 Shikhar Bhushan
                    while data:
134 0fd74489 Shikhar Bhushan
                        n = chan.send(data)
135 0fd74489 Shikhar Bhushan
                        if n <= 0:
136 38a9b062 Shikhar Bhushan
                            raise SessionCloseError(self._in_buf.getvalue(), data)
137 0fd74489 Shikhar Bhushan
                        data = data[n:]
138 0fd74489 Shikhar Bhushan
                if chan.recv_ready():
139 3ad93428 Shikhar Bhushan
                    data = chan.recv(SSHSession.BUF_SIZE)
140 0fd74489 Shikhar Bhushan
                    if data:
141 38a9b062 Shikhar Bhushan
                        self._in_buf.write(data)
142 3ad93428 Shikhar Bhushan
                        self._fresh_data()
143 0fd74489 Shikhar Bhushan
                    else:
144 38a9b062 Shikhar Bhushan
                        raise SessionCloseError(self._in_buf.getvalue())
145 0fd74489 Shikhar Bhushan
        except Exception as e:
146 38a9b062 Shikhar Bhushan
            logger.debug('*** broke out of main loop ***')
147 0fd74489 Shikhar Bhushan
            self.dispatch('error', e)
148 589b23e4 Shikhar Bhushan
149 589b23e4 Shikhar Bhushan
class MissingHostKeyPolicy(paramiko.MissingHostKeyPolicy):
150 589b23e4 Shikhar Bhushan
    
151 589b23e4 Shikhar Bhushan
    def __init__(self, cb):
152 589b23e4 Shikhar Bhushan
        self._cb = cb
153 589b23e4 Shikhar Bhushan
    
154 589b23e4 Shikhar Bhushan
    def missing_host_key(self, client, hostname, key):
155 589b23e4 Shikhar Bhushan
        if not self._cb(hostname, key):
156 35ad9d81 Shikhar Bhushan
            raise SSHError