1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """
20 Implementation of an SSH2 "message".
21 """
22
23 import struct
24 import cStringIO
25
26 from paramiko import util
27
28
30 """
31 An SSH2 I{Message} is a stream of bytes that encodes some combination of
32 strings, integers, bools, and infinite-precision integers (known in python
33 as I{long}s). This class builds or breaks down such a byte stream.
34
35 Normally you don't need to deal with anything this low-level, but it's
36 exposed for people implementing custom extensions, or features that
37 paramiko doesn't support yet.
38 """
39
41 """
42 Create a new SSH2 Message.
43
44 @param content: the byte stream to use as the Message content (passed
45 in only when decomposing a Message).
46 @type content: string
47 """
48 if content != None:
49 self.packet = cStringIO.StringIO(content)
50 else:
51 self.packet = cStringIO.StringIO()
52
54 """
55 Return the byte stream content of this Message, as a string.
56
57 @return: the contents of this Message.
58 @rtype: string
59 """
60 return self.packet.getvalue()
61
63 """
64 Returns a string representation of this object, for debugging.
65
66 @rtype: string
67 """
68 return 'paramiko.Message(' + repr(self.packet.getvalue()) + ')'
69
71 """
72 Rewind the message to the beginning as if no items had been parsed
73 out of it yet.
74 """
75 self.packet.seek(0)
76
77 - def get_remainder(self):
78 """
79 Return the bytes of this Message that haven't already been parsed and
80 returned.
81
82 @return: a string of the bytes not parsed yet.
83 @rtype: string
84 """
85 position = self.packet.tell()
86 remainder = self.packet.read()
87 self.packet.seek(position)
88 return remainder
89
91 """
92 Returns the bytes of this Message that have been parsed and returned.
93 The string passed into a Message's constructor can be regenerated by
94 concatenating C{get_so_far} and L{get_remainder}.
95
96 @return: a string of the bytes parsed so far.
97 @rtype: string
98 """
99 position = self.packet.tell()
100 self.rewind()
101 return self.packet.read(position)
102
104 """
105 Return the next C{n} bytes of the Message, without decomposing into
106 an int, string, etc. Just the raw bytes are returned.
107
108 @return: a string of the next C{n} bytes of the Message, or a string
109 of C{n} zero bytes, if there aren't C{n} bytes remaining.
110 @rtype: string
111 """
112 b = self.packet.read(n)
113 max_pad_size = 1<<20
114 if len(b) < n and n < max_pad_size:
115 return b + '\x00' * (n - len(b))
116 return b
117
119 """
120 Return the next byte of the Message, without decomposing it. This
121 is equivalent to L{get_bytes(1)<get_bytes>}.
122
123 @return: the next byte of the Message, or C{'\000'} if there aren't
124 any bytes remaining.
125 @rtype: string
126 """
127 return self.get_bytes(1)
128
130 """
131 Fetch a boolean from the stream.
132
133 @return: C{True} or C{False} (from the Message).
134 @rtype: bool
135 """
136 b = self.get_bytes(1)
137 return b != '\x00'
138
140 """
141 Fetch an int from the stream.
142
143 @return: a 32-bit unsigned integer.
144 @rtype: int
145 """
146 return struct.unpack('>I', self.get_bytes(4))[0]
147
149 """
150 Fetch a 64-bit int from the stream.
151
152 @return: a 64-bit unsigned integer.
153 @rtype: long
154 """
155 return struct.unpack('>Q', self.get_bytes(8))[0]
156
158 """
159 Fetch a long int (mpint) from the stream.
160
161 @return: an arbitrary-length integer.
162 @rtype: long
163 """
164 return util.inflate_long(self.get_string())
165
167 """
168 Fetch a string from the stream. This could be a byte string and may
169 contain unprintable characters. (It's not unheard of for a string to
170 contain another byte-stream Message.)
171
172 @return: a string.
173 @rtype: string
174 """
175 return self.get_bytes(self.get_int())
176
178 """
179 Fetch a list of strings from the stream. These are trivially encoded
180 as comma-separated values in a string.
181
182 @return: a list of strings.
183 @rtype: list of strings
184 """
185 return self.get_string().split(',')
186
188 """
189 Write bytes to the stream, without any formatting.
190
191 @param b: bytes to add
192 @type b: str
193 """
194 self.packet.write(b)
195 return self
196
198 """
199 Write a single byte to the stream, without any formatting.
200
201 @param b: byte to add
202 @type b: str
203 """
204 self.packet.write(b)
205 return self
206
208 """
209 Add a boolean value to the stream.
210
211 @param b: boolean value to add
212 @type b: bool
213 """
214 if b:
215 self.add_byte('\x01')
216 else:
217 self.add_byte('\x00')
218 return self
219
221 """
222 Add an integer to the stream.
223
224 @param n: integer to add
225 @type n: int
226 """
227 self.packet.write(struct.pack('>I', n))
228 return self
229
231 """
232 Add a 64-bit int to the stream.
233
234 @param n: long int to add
235 @type n: long
236 """
237 self.packet.write(struct.pack('>Q', n))
238 return self
239
241 """
242 Add a long int to the stream, encoded as an infinite-precision
243 integer. This method only works on positive numbers.
244
245 @param z: long int to add
246 @type z: long
247 """
248 self.add_string(util.deflate_long(z))
249 return self
250
252 """
253 Add a string to the stream.
254
255 @param s: string to add
256 @type s: str
257 """
258 self.add_int(len(s))
259 self.packet.write(s)
260 return self
261
263 """
264 Add a list of strings to the stream. They are encoded identically to
265 a single string of values separated by commas. (Yes, really, that's
266 how SSH2 does it.)
267
268 @param l: list of strings to add
269 @type l: list(str)
270 """
271 self.add_string(','.join(l))
272 return self
273
275 if type(i) is str:
276 return self.add_string(i)
277 elif type(i) is int:
278 return self.add_int(i)
279 elif type(i) is long:
280 if i > 0xffffffffL:
281 return self.add_mpint(i)
282 else:
283 return self.add_int(i)
284 elif type(i) is bool:
285 return self.add_boolean(i)
286 elif type(i) is list:
287 return self.add_list(i)
288 else:
289 raise Exception('Unknown type')
290
291 - def add(self, *seq):
292 """
293 Add a sequence of items to the stream. The values are encoded based
294 on their type: str, int, bool, list, or long.
295
296 @param seq: the sequence of items
297 @type seq: sequence
298
299 @bug: longs are encoded non-deterministically. Don't use this method.
300 """
301 for item in seq:
302 self._add(item)
303