1 | #include <windows.h>
|
---|
2 | #include <stdio.h>
|
---|
3 | #include <stdlib.h>
|
---|
4 | #include <stdarg.h>
|
---|
5 | #include <assert.h>
|
---|
6 | #include "FzSFtpIpc.h"
|
---|
7 |
|
---|
8 | #include "putty.h"
|
---|
9 | #include "tree234.h"
|
---|
10 | #include "ssh.h"
|
---|
11 |
|
---|
12 | #ifndef FALSE
|
---|
13 | #define FALSE 0
|
---|
14 | #endif
|
---|
15 | #ifndef TRUE
|
---|
16 | #define TRUE 1
|
---|
17 | #endif
|
---|
18 |
|
---|
19 | /* logevent, only printf-formatted. */
|
---|
20 | void logeventf(char *fmt, ...)
|
---|
21 | {
|
---|
22 | va_list ap;
|
---|
23 | char stuff[200];
|
---|
24 |
|
---|
25 | va_start(ap, fmt);
|
---|
26 | vsprintf(stuff, fmt, ap);
|
---|
27 | va_end(ap);
|
---|
28 | logevent(stuff);
|
---|
29 | }
|
---|
30 |
|
---|
31 | #define bombout(msg) ( ssh_state = SSH_STATE_CLOSED, \
|
---|
32 | (s ? sk_close(s), s = NULL : 0), \
|
---|
33 | connection_fatal msg )
|
---|
34 |
|
---|
35 | #define SSH1_MSG_DISCONNECT 1 /* 0x1 */
|
---|
36 | #define SSH1_SMSG_PUBLIC_KEY 2 /* 0x2 */
|
---|
37 | #define SSH1_CMSG_SESSION_KEY 3 /* 0x3 */
|
---|
38 | #define SSH1_CMSG_USER 4 /* 0x4 */
|
---|
39 | #define SSH1_CMSG_AUTH_RSA 6 /* 0x6 */
|
---|
40 | #define SSH1_SMSG_AUTH_RSA_CHALLENGE 7 /* 0x7 */
|
---|
41 | #define SSH1_CMSG_AUTH_RSA_RESPONSE 8 /* 0x8 */
|
---|
42 | #define SSH1_CMSG_AUTH_PASSWORD 9 /* 0x9 */
|
---|
43 | #define SSH1_CMSG_REQUEST_PTY 10 /* 0xa */
|
---|
44 | #define SSH1_CMSG_WINDOW_SIZE 11 /* 0xb */
|
---|
45 | #define SSH1_CMSG_EXEC_SHELL 12 /* 0xc */
|
---|
46 | #define SSH1_CMSG_EXEC_CMD 13 /* 0xd */
|
---|
47 | #define SSH1_SMSG_SUCCESS 14 /* 0xe */
|
---|
48 | #define SSH1_SMSG_FAILURE 15 /* 0xf */
|
---|
49 | #define SSH1_CMSG_STDIN_DATA 16 /* 0x10 */
|
---|
50 | #define SSH1_SMSG_STDOUT_DATA 17 /* 0x11 */
|
---|
51 | #define SSH1_SMSG_STDERR_DATA 18 /* 0x12 */
|
---|
52 | #define SSH1_CMSG_EOF 19 /* 0x13 */
|
---|
53 | #define SSH1_SMSG_EXIT_STATUS 20 /* 0x14 */
|
---|
54 | #define SSH1_MSG_CHANNEL_OPEN_CONFIRMATION 21 /* 0x15 */
|
---|
55 | #define SSH1_MSG_CHANNEL_OPEN_FAILURE 22 /* 0x16 */
|
---|
56 | #define SSH1_MSG_CHANNEL_DATA 23 /* 0x17 */
|
---|
57 | #define SSH1_MSG_CHANNEL_CLOSE 24 /* 0x18 */
|
---|
58 | #define SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION 25 /* 0x19 */
|
---|
59 | #define SSH1_SMSG_X11_OPEN 27 /* 0x1b */
|
---|
60 | #define SSH1_CMSG_PORT_FORWARD_REQUEST 28 /* 0x1c */
|
---|
61 | #define SSH1_MSG_PORT_OPEN 29 /* 0x1d */
|
---|
62 | #define SSH1_CMSG_AGENT_REQUEST_FORWARDING 30 /* 0x1e */
|
---|
63 | #define SSH1_SMSG_AGENT_OPEN 31 /* 0x1f */
|
---|
64 | #define SSH1_MSG_IGNORE 32 /* 0x20 */
|
---|
65 | #define SSH1_CMSG_EXIT_CONFIRMATION 33 /* 0x21 */
|
---|
66 | #define SSH1_CMSG_X11_REQUEST_FORWARDING 34 /* 0x22 */
|
---|
67 | #define SSH1_CMSG_AUTH_RHOSTS_RSA 35 /* 0x23 */
|
---|
68 | #define SSH1_MSG_DEBUG 36 /* 0x24 */
|
---|
69 | #define SSH1_CMSG_REQUEST_COMPRESSION 37 /* 0x25 */
|
---|
70 | #define SSH1_CMSG_AUTH_TIS 39 /* 0x27 */
|
---|
71 | #define SSH1_SMSG_AUTH_TIS_CHALLENGE 40 /* 0x28 */
|
---|
72 | #define SSH1_CMSG_AUTH_TIS_RESPONSE 41 /* 0x29 */
|
---|
73 | #define SSH1_CMSG_AUTH_CCARD 70 /* 0x46 */
|
---|
74 | #define SSH1_SMSG_AUTH_CCARD_CHALLENGE 71 /* 0x47 */
|
---|
75 | #define SSH1_CMSG_AUTH_CCARD_RESPONSE 72 /* 0x48 */
|
---|
76 |
|
---|
77 | #define SSH1_AUTH_TIS 5 /* 0x5 */
|
---|
78 | #define SSH1_AUTH_CCARD 16 /* 0x10 */
|
---|
79 |
|
---|
80 | #define SSH1_PROTOFLAG_SCREEN_NUMBER 1 /* 0x1 */
|
---|
81 | /* Mask for protoflags we will echo back to server if seen */
|
---|
82 | #define SSH1_PROTOFLAGS_SUPPORTED 0 /* 0x1 */
|
---|
83 |
|
---|
84 | #define SSH2_MSG_DISCONNECT 1 /* 0x1 */
|
---|
85 | #define SSH2_MSG_IGNORE 2 /* 0x2 */
|
---|
86 | #define SSH2_MSG_UNIMPLEMENTED 3 /* 0x3 */
|
---|
87 | #define SSH2_MSG_DEBUG 4 /* 0x4 */
|
---|
88 | #define SSH2_MSG_SERVICE_REQUEST 5 /* 0x5 */
|
---|
89 | #define SSH2_MSG_SERVICE_ACCEPT 6 /* 0x6 */
|
---|
90 | #define SSH2_MSG_KEXINIT 20 /* 0x14 */
|
---|
91 | #define SSH2_MSG_NEWKEYS 21 /* 0x15 */
|
---|
92 | #define SSH2_MSG_KEXDH_INIT 30 /* 0x1e */
|
---|
93 | #define SSH2_MSG_KEXDH_REPLY 31 /* 0x1f */
|
---|
94 | #define SSH2_MSG_KEX_DH_GEX_REQUEST 30 /* 0x1e */
|
---|
95 | #define SSH2_MSG_KEX_DH_GEX_GROUP 31 /* 0x1f */
|
---|
96 | #define SSH2_MSG_KEX_DH_GEX_INIT 32 /* 0x20 */
|
---|
97 | #define SSH2_MSG_KEX_DH_GEX_REPLY 33 /* 0x21 */
|
---|
98 | #define SSH2_MSG_USERAUTH_REQUEST 50 /* 0x32 */
|
---|
99 | #define SSH2_MSG_USERAUTH_FAILURE 51 /* 0x33 */
|
---|
100 | #define SSH2_MSG_USERAUTH_SUCCESS 52 /* 0x34 */
|
---|
101 | #define SSH2_MSG_USERAUTH_BANNER 53 /* 0x35 */
|
---|
102 | #define SSH2_MSG_USERAUTH_PK_OK 60 /* 0x3c */
|
---|
103 | #define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60 /* 0x3c */
|
---|
104 | #define SSH2_MSG_USERAUTH_INFO_REQUEST 60 /* 0x3c */
|
---|
105 | #define SSH2_MSG_USERAUTH_INFO_RESPONSE 61 /* 0x3d */
|
---|
106 | #define SSH2_MSG_GLOBAL_REQUEST 80 /* 0x50 */
|
---|
107 | #define SSH2_MSG_REQUEST_SUCCESS 81 /* 0x51 */
|
---|
108 | #define SSH2_MSG_REQUEST_FAILURE 82 /* 0x52 */
|
---|
109 | #define SSH2_MSG_CHANNEL_OPEN 90 /* 0x5a */
|
---|
110 | #define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91 /* 0x5b */
|
---|
111 | #define SSH2_MSG_CHANNEL_OPEN_FAILURE 92 /* 0x5c */
|
---|
112 | #define SSH2_MSG_CHANNEL_WINDOW_ADJUST 93 /* 0x5d */
|
---|
113 | #define SSH2_MSG_CHANNEL_DATA 94 /* 0x5e */
|
---|
114 | #define SSH2_MSG_CHANNEL_EXTENDED_DATA 95 /* 0x5f */
|
---|
115 | #define SSH2_MSG_CHANNEL_EOF 96 /* 0x60 */
|
---|
116 | #define SSH2_MSG_CHANNEL_CLOSE 97 /* 0x61 */
|
---|
117 | #define SSH2_MSG_CHANNEL_REQUEST 98 /* 0x62 */
|
---|
118 | #define SSH2_MSG_CHANNEL_SUCCESS 99 /* 0x63 */
|
---|
119 | #define SSH2_MSG_CHANNEL_FAILURE 100 /* 0x64 */
|
---|
120 |
|
---|
121 | /*
|
---|
122 | * Packet type contexts, so that ssh2_pkt_type can correctly decode
|
---|
123 | * the ambiguous type numbers back into the correct type strings.
|
---|
124 | */
|
---|
125 | #define SSH2_PKTCTX_DHGROUP1 0x0001
|
---|
126 | #define SSH2_PKTCTX_DHGEX 0x0002
|
---|
127 | #define SSH2_PKTCTX_PUBLICKEY 0x0010
|
---|
128 | #define SSH2_PKTCTX_PASSWORD 0x0020
|
---|
129 | #define SSH2_PKTCTX_KBDINTER 0x0040
|
---|
130 | #define SSH2_PKTCTX_AUTH_MASK 0x00F0
|
---|
131 |
|
---|
132 | #define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 /* 0x1 */
|
---|
133 | #define SSH2_DISCONNECT_PROTOCOL_ERROR 2 /* 0x2 */
|
---|
134 | #define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED 3 /* 0x3 */
|
---|
135 | #define SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED 4 /* 0x4 */
|
---|
136 | #define SSH2_DISCONNECT_MAC_ERROR 5 /* 0x5 */
|
---|
137 | #define SSH2_DISCONNECT_COMPRESSION_ERROR 6 /* 0x6 */
|
---|
138 | #define SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE 7 /* 0x7 */
|
---|
139 | #define SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 /* 0x8 */
|
---|
140 | #define SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 /* 0x9 */
|
---|
141 | #define SSH2_DISCONNECT_CONNECTION_LOST 10 /* 0xa */
|
---|
142 | #define SSH2_DISCONNECT_BY_APPLICATION 11 /* 0xb */
|
---|
143 | #define SSH2_DISCONNECT_TOO_MANY_CONNECTIONS 12 /* 0xc */
|
---|
144 | #define SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER 13 /* 0xd */
|
---|
145 | #define SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 /* 0xe */
|
---|
146 | #define SSH2_DISCONNECT_ILLEGAL_USER_NAME 15 /* 0xf */
|
---|
147 |
|
---|
148 | static const char *const ssh2_disconnect_reasons[] = {
|
---|
149 | NULL,
|
---|
150 | "SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT",
|
---|
151 | "SSH_DISCONNECT_PROTOCOL_ERROR",
|
---|
152 | "SSH_DISCONNECT_KEY_EXCHANGE_FAILED",
|
---|
153 | "SSH_DISCONNECT_HOST_AUTHENTICATION_FAILED",
|
---|
154 | "SSH_DISCONNECT_MAC_ERROR",
|
---|
155 | "SSH_DISCONNECT_COMPRESSION_ERROR",
|
---|
156 | "SSH_DISCONNECT_SERVICE_NOT_AVAILABLE",
|
---|
157 | "SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED",
|
---|
158 | "SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE",
|
---|
159 | "SSH_DISCONNECT_CONNECTION_LOST",
|
---|
160 | "SSH_DISCONNECT_BY_APPLICATION",
|
---|
161 | "SSH_DISCONNECT_TOO_MANY_CONNECTIONS",
|
---|
162 | "SSH_DISCONNECT_AUTH_CANCELLED_BY_USER",
|
---|
163 | "SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE",
|
---|
164 | "SSH_DISCONNECT_ILLEGAL_USER_NAME",
|
---|
165 | };
|
---|
166 |
|
---|
167 | #define SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED 1 /* 0x1 */
|
---|
168 | #define SSH2_OPEN_CONNECT_FAILED 2 /* 0x2 */
|
---|
169 | #define SSH2_OPEN_UNKNOWN_CHANNEL_TYPE 3 /* 0x3 */
|
---|
170 | #define SSH2_OPEN_RESOURCE_SHORTAGE 4 /* 0x4 */
|
---|
171 |
|
---|
172 | #define SSH2_EXTENDED_DATA_STDERR 1 /* 0x1 */
|
---|
173 |
|
---|
174 | /*
|
---|
175 | * Various remote-bug flags.
|
---|
176 | */
|
---|
177 | #define BUG_CHOKES_ON_SSH1_IGNORE 1
|
---|
178 | #define BUG_SSH2_HMAC 2
|
---|
179 | #define BUG_NEEDS_SSH1_PLAIN_PASSWORD 4
|
---|
180 | #define BUG_CHOKES_ON_RSA 8
|
---|
181 | #define BUG_SSH2_RSA_PADDING 16
|
---|
182 | #define BUG_SSH2_DERIVEKEY 32
|
---|
183 |
|
---|
184 |
|
---|
185 | static int ssh_pkt_ctx = 0;
|
---|
186 |
|
---|
187 | #define translate(x) if (type == x) return #x
|
---|
188 | #define translatec(x,ctx) if (type == x && (ssh_pkt_ctx & ctx)) return #x
|
---|
189 | char *ssh1_pkt_type(int type)
|
---|
190 | {
|
---|
191 | translate(SSH1_MSG_DISCONNECT);
|
---|
192 | translate(SSH1_SMSG_PUBLIC_KEY);
|
---|
193 | translate(SSH1_CMSG_SESSION_KEY);
|
---|
194 | translate(SSH1_CMSG_USER);
|
---|
195 | translate(SSH1_CMSG_AUTH_RSA);
|
---|
196 | translate(SSH1_SMSG_AUTH_RSA_CHALLENGE);
|
---|
197 | translate(SSH1_CMSG_AUTH_RSA_RESPONSE);
|
---|
198 | translate(SSH1_CMSG_AUTH_PASSWORD);
|
---|
199 | translate(SSH1_CMSG_REQUEST_PTY);
|
---|
200 | translate(SSH1_CMSG_WINDOW_SIZE);
|
---|
201 | translate(SSH1_CMSG_EXEC_SHELL);
|
---|
202 | translate(SSH1_CMSG_EXEC_CMD);
|
---|
203 | translate(SSH1_SMSG_SUCCESS);
|
---|
204 | translate(SSH1_SMSG_FAILURE);
|
---|
205 | translate(SSH1_CMSG_STDIN_DATA);
|
---|
206 | translate(SSH1_SMSG_STDOUT_DATA);
|
---|
207 | translate(SSH1_SMSG_STDERR_DATA);
|
---|
208 | translate(SSH1_CMSG_EOF);
|
---|
209 | translate(SSH1_SMSG_EXIT_STATUS);
|
---|
210 | translate(SSH1_MSG_CHANNEL_OPEN_CONFIRMATION);
|
---|
211 | translate(SSH1_MSG_CHANNEL_OPEN_FAILURE);
|
---|
212 | translate(SSH1_MSG_CHANNEL_DATA);
|
---|
213 | translate(SSH1_MSG_CHANNEL_CLOSE);
|
---|
214 | translate(SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION);
|
---|
215 | translate(SSH1_SMSG_X11_OPEN);
|
---|
216 | translate(SSH1_CMSG_PORT_FORWARD_REQUEST);
|
---|
217 | translate(SSH1_MSG_PORT_OPEN);
|
---|
218 | translate(SSH1_CMSG_AGENT_REQUEST_FORWARDING);
|
---|
219 | translate(SSH1_SMSG_AGENT_OPEN);
|
---|
220 | translate(SSH1_MSG_IGNORE);
|
---|
221 | translate(SSH1_CMSG_EXIT_CONFIRMATION);
|
---|
222 | translate(SSH1_CMSG_X11_REQUEST_FORWARDING);
|
---|
223 | translate(SSH1_CMSG_AUTH_RHOSTS_RSA);
|
---|
224 | translate(SSH1_MSG_DEBUG);
|
---|
225 | translate(SSH1_CMSG_REQUEST_COMPRESSION);
|
---|
226 | translate(SSH1_CMSG_AUTH_TIS);
|
---|
227 | translate(SSH1_SMSG_AUTH_TIS_CHALLENGE);
|
---|
228 | translate(SSH1_CMSG_AUTH_TIS_RESPONSE);
|
---|
229 | translate(SSH1_CMSG_AUTH_CCARD);
|
---|
230 | translate(SSH1_SMSG_AUTH_CCARD_CHALLENGE);
|
---|
231 | translate(SSH1_CMSG_AUTH_CCARD_RESPONSE);
|
---|
232 | return "unknown";
|
---|
233 | }
|
---|
234 | char *ssh2_pkt_type(int type)
|
---|
235 | {
|
---|
236 | translate(SSH2_MSG_DISCONNECT);
|
---|
237 | translate(SSH2_MSG_IGNORE);
|
---|
238 | translate(SSH2_MSG_UNIMPLEMENTED);
|
---|
239 | translate(SSH2_MSG_DEBUG);
|
---|
240 | translate(SSH2_MSG_SERVICE_REQUEST);
|
---|
241 | translate(SSH2_MSG_SERVICE_ACCEPT);
|
---|
242 | translate(SSH2_MSG_KEXINIT);
|
---|
243 | translate(SSH2_MSG_NEWKEYS);
|
---|
244 | translatec(SSH2_MSG_KEXDH_INIT, SSH2_PKTCTX_DHGROUP1);
|
---|
245 | translatec(SSH2_MSG_KEXDH_REPLY, SSH2_PKTCTX_DHGROUP1);
|
---|
246 | translatec(SSH2_MSG_KEX_DH_GEX_REQUEST, SSH2_PKTCTX_DHGEX);
|
---|
247 | translatec(SSH2_MSG_KEX_DH_GEX_GROUP, SSH2_PKTCTX_DHGEX);
|
---|
248 | translatec(SSH2_MSG_KEX_DH_GEX_INIT, SSH2_PKTCTX_DHGEX);
|
---|
249 | translatec(SSH2_MSG_KEX_DH_GEX_REPLY, SSH2_PKTCTX_DHGEX);
|
---|
250 | translate(SSH2_MSG_USERAUTH_REQUEST);
|
---|
251 | translate(SSH2_MSG_USERAUTH_FAILURE);
|
---|
252 | translate(SSH2_MSG_USERAUTH_SUCCESS);
|
---|
253 | translate(SSH2_MSG_USERAUTH_BANNER);
|
---|
254 | translatec(SSH2_MSG_USERAUTH_PK_OK, SSH2_PKTCTX_PUBLICKEY);
|
---|
255 | translatec(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, SSH2_PKTCTX_PASSWORD);
|
---|
256 | translatec(SSH2_MSG_USERAUTH_INFO_REQUEST, SSH2_PKTCTX_KBDINTER);
|
---|
257 | translatec(SSH2_MSG_USERAUTH_INFO_RESPONSE, SSH2_PKTCTX_KBDINTER);
|
---|
258 | translate(SSH2_MSG_GLOBAL_REQUEST);
|
---|
259 | translate(SSH2_MSG_REQUEST_SUCCESS);
|
---|
260 | translate(SSH2_MSG_REQUEST_FAILURE);
|
---|
261 | translate(SSH2_MSG_CHANNEL_OPEN);
|
---|
262 | translate(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
|
---|
263 | translate(SSH2_MSG_CHANNEL_OPEN_FAILURE);
|
---|
264 | translate(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
|
---|
265 | translate(SSH2_MSG_CHANNEL_DATA);
|
---|
266 | translate(SSH2_MSG_CHANNEL_EXTENDED_DATA);
|
---|
267 | translate(SSH2_MSG_CHANNEL_EOF);
|
---|
268 | translate(SSH2_MSG_CHANNEL_CLOSE);
|
---|
269 | translate(SSH2_MSG_CHANNEL_REQUEST);
|
---|
270 | translate(SSH2_MSG_CHANNEL_SUCCESS);
|
---|
271 | translate(SSH2_MSG_CHANNEL_FAILURE);
|
---|
272 | return "unknown";
|
---|
273 | }
|
---|
274 | #undef translate
|
---|
275 | #undef translatec
|
---|
276 |
|
---|
277 | #define GET_32BIT(cp) \
|
---|
278 | (((unsigned long)(unsigned char)(cp)[0] << 24) | \
|
---|
279 | ((unsigned long)(unsigned char)(cp)[1] << 16) | \
|
---|
280 | ((unsigned long)(unsigned char)(cp)[2] << 8) | \
|
---|
281 | ((unsigned long)(unsigned char)(cp)[3]))
|
---|
282 |
|
---|
283 | #define PUT_32BIT(cp, value) { \
|
---|
284 | (cp)[0] = (unsigned char)((value) >> 24); \
|
---|
285 | (cp)[1] = (unsigned char)((value) >> 16); \
|
---|
286 | (cp)[2] = (unsigned char)((value) >> 8); \
|
---|
287 | (cp)[3] = (unsigned char)(value); }
|
---|
288 |
|
---|
289 | enum { PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM };
|
---|
290 |
|
---|
291 | /* Coroutine mechanics for the sillier bits of the code */
|
---|
292 | #define crBegin1 static int crLine = 0;
|
---|
293 | #define crBegin2 switch(crLine) { case 0:;
|
---|
294 | #define crBegin crBegin1; crBegin2;
|
---|
295 | #define crFinish(z) } crLine = 0; return (z)
|
---|
296 | #define crFinishV } crLine = 0; return
|
---|
297 | #define crReturn(z) \
|
---|
298 | do {\
|
---|
299 | crLine=__LINE__; return (z); case __LINE__:;\
|
---|
300 | } while (0)
|
---|
301 | #define crReturnV \
|
---|
302 | do {\
|
---|
303 | crLine=__LINE__; return; case __LINE__:;\
|
---|
304 | } while (0)
|
---|
305 | #define crStop(z) do{ crLine = 0; return (z); }while(0)
|
---|
306 | #define crStopV do{ crLine = 0; return; }while(0)
|
---|
307 | #define crWaitUntil(c) do { crReturn(0); } while (!(c))
|
---|
308 | #define crWaitUntilV(c) do { crReturnV; } while (!(c))
|
---|
309 |
|
---|
310 | /*extern char *x11_init(Socket *, char *, void *);
|
---|
311 | extern void x11_close(Socket);
|
---|
312 | extern int x11_send(Socket, char *, int);
|
---|
313 | extern void x11_invent_auth(char *, int, char *, int);
|
---|
314 | extern void x11_unthrottle(Socket s);
|
---|
315 | extern void x11_override_throttle(Socket s, int enable);*/
|
---|
316 |
|
---|
317 | extern char *pfd_newconnect(Socket * s, char *hostname, int port, void *c);
|
---|
318 | extern char *pfd_addforward(char *desthost, int destport, int port);
|
---|
319 | extern void pfd_close(Socket s);
|
---|
320 | extern int pfd_send(Socket s, char *data, int len);
|
---|
321 | extern void pfd_confirm(Socket s);
|
---|
322 | extern void pfd_unthrottle(Socket s);
|
---|
323 | extern void pfd_override_throttle(Socket s, int enable);
|
---|
324 |
|
---|
325 | static void ssh2_pkt_init(int pkt_type);
|
---|
326 | static void ssh2_pkt_addbool(unsigned char value);
|
---|
327 | static void ssh2_pkt_adduint32(unsigned long value);
|
---|
328 | static void ssh2_pkt_addstring_start(void);
|
---|
329 | static void ssh2_pkt_addstring_str(char *data);
|
---|
330 | static void ssh2_pkt_addstring_data(char *data, int len);
|
---|
331 | static void ssh2_pkt_addstring(char *data);
|
---|
332 | static char *ssh2_mpint_fmt(Bignum b, int *len);
|
---|
333 | static void ssh2_pkt_addmp(Bignum b);
|
---|
334 | static int ssh2_pkt_construct(void);
|
---|
335 | static void ssh2_pkt_send(void);
|
---|
336 |
|
---|
337 | /*
|
---|
338 | * Buffer management constants. There are several of these for
|
---|
339 | * various different purposes:
|
---|
340 | *
|
---|
341 | * - SSH1_BUFFER_LIMIT is the amount of backlog that must build up
|
---|
342 | * on a local data stream before we throttle the whole SSH
|
---|
343 | * connection (in SSH1 only). Throttling the whole connection is
|
---|
344 | * pretty drastic so we set this high in the hope it won't
|
---|
345 | * happen very often.
|
---|
346 | *
|
---|
347 | * - SSH_MAX_BACKLOG is the amount of backlog that must build up
|
---|
348 | * on the SSH connection itself before we defensively throttle
|
---|
349 | * _all_ local data streams. This is pretty drastic too (though
|
---|
350 | * thankfully unlikely in SSH2 since the window mechanism should
|
---|
351 | * ensure that the server never has any need to throttle its end
|
---|
352 | * of the connection), so we set this high as well.
|
---|
353 | *
|
---|
354 | * - OUR_V2_WINSIZE is the maximum window size we present on SSH2
|
---|
355 | * channels.
|
---|
356 | */
|
---|
357 |
|
---|
358 | #define SSH1_BUFFER_LIMIT 32768
|
---|
359 | #define SSH_MAX_BACKLOG 32768
|
---|
360 | #define OUR_V2_WINSIZE 16384
|
---|
361 |
|
---|
362 | const static struct ssh_kex *kex_algs[] = {
|
---|
363 | &ssh_diffiehellman_gex,
|
---|
364 | &ssh_diffiehellman
|
---|
365 | };
|
---|
366 |
|
---|
367 | const static struct ssh_signkey *hostkey_algs[] = { &ssh_rsa, &ssh_dss };
|
---|
368 |
|
---|
369 | static void nullmac_key(unsigned char *key)
|
---|
370 | {
|
---|
371 | }
|
---|
372 | static void nullmac_generate(unsigned char *blk, int len,
|
---|
373 | unsigned long seq)
|
---|
374 | {
|
---|
375 | }
|
---|
376 | static int nullmac_verify(unsigned char *blk, int len, unsigned long seq)
|
---|
377 | {
|
---|
378 | return 1;
|
---|
379 | }
|
---|
380 | const static struct ssh_mac ssh_mac_none = {
|
---|
381 | nullmac_key, nullmac_key, nullmac_generate, nullmac_verify, "none", 0
|
---|
382 | };
|
---|
383 | const static struct ssh_mac *macs[] = {
|
---|
384 | &ssh_sha1, &ssh_md5, &ssh_mac_none
|
---|
385 | };
|
---|
386 | const static struct ssh_mac *buggymacs[] = {
|
---|
387 | &ssh_sha1_buggy, &ssh_md5, &ssh_mac_none
|
---|
388 | };
|
---|
389 |
|
---|
390 | static void ssh_comp_none_init(void)
|
---|
391 | {
|
---|
392 | }
|
---|
393 | static int ssh_comp_none_block(unsigned char *block, int len,
|
---|
394 | unsigned char **outblock, int *outlen)
|
---|
395 | {
|
---|
396 | return 0;
|
---|
397 | }
|
---|
398 | static int ssh_comp_none_disable(void)
|
---|
399 | {
|
---|
400 | return 0;
|
---|
401 | }
|
---|
402 | const static struct ssh_compress ssh_comp_none = {
|
---|
403 | "none",
|
---|
404 | ssh_comp_none_init, ssh_comp_none_block,
|
---|
405 | ssh_comp_none_init, ssh_comp_none_block,
|
---|
406 | ssh_comp_none_disable
|
---|
407 | };
|
---|
408 | extern const struct ssh_compress ssh_zlib;
|
---|
409 | const static struct ssh_compress *compressions[] = {
|
---|
410 | &ssh_zlib, &ssh_comp_none
|
---|
411 | };
|
---|
412 |
|
---|
413 | enum { /* channel types */
|
---|
414 | CHAN_MAINSESSION,
|
---|
415 | CHAN_X11,
|
---|
416 | CHAN_AGENT,
|
---|
417 | CHAN_SOCKDATA,
|
---|
418 | CHAN_SOCKDATA_DORMANT /* one the remote hasn't confirmed */
|
---|
419 | };
|
---|
420 |
|
---|
421 | /*
|
---|
422 | * 2-3-4 tree storing channels.
|
---|
423 | */
|
---|
424 | struct ssh_channel {
|
---|
425 | unsigned remoteid, localid;
|
---|
426 | int type;
|
---|
427 | int closes;
|
---|
428 | union {
|
---|
429 | struct ssh1_data_channel {
|
---|
430 | int throttling;
|
---|
431 | } v1;
|
---|
432 | struct ssh2_data_channel {
|
---|
433 | bufchain outbuffer;
|
---|
434 | unsigned remwindow, remmaxpkt;
|
---|
435 | unsigned locwindow;
|
---|
436 | } v2;
|
---|
437 | } v;
|
---|
438 | union {
|
---|
439 | struct ssh_agent_channel {
|
---|
440 | unsigned char *message;
|
---|
441 | unsigned char msglen[4];
|
---|
442 | int lensofar, totallen;
|
---|
443 | } a;
|
---|
444 | struct ssh_x11_channel {
|
---|
445 | Socket s;
|
---|
446 | } x11;
|
---|
447 | struct ssh_pfd_channel {
|
---|
448 | Socket s;
|
---|
449 | } pfd;
|
---|
450 | } u;
|
---|
451 | };
|
---|
452 |
|
---|
453 | /*
|
---|
454 | * 2-3-4 tree storing remote->local port forwardings. SSH 1 and SSH
|
---|
455 | * 2 use this structure in different ways, reflecting SSH 2's
|
---|
456 | * altogether saner approach to port forwarding.
|
---|
457 | *
|
---|
458 | * In SSH 1, you arrange a remote forwarding by sending the server
|
---|
459 | * the remote port number, and the local destination host:port.
|
---|
460 | * When a connection comes in, the server sends you back that
|
---|
461 | * host:port pair, and you connect to it. This is a ready-made
|
---|
462 | * security hole if you're not on the ball: a malicious server
|
---|
463 | * could send you back _any_ host:port pair, so if you trustingly
|
---|
464 | * connect to the address it gives you then you've just opened the
|
---|
465 | * entire inside of your corporate network just by connecting
|
---|
466 | * through it to a dodgy SSH server. Hence, we must store a list of
|
---|
467 | * host:port pairs we _are_ trying to forward to, and reject a
|
---|
468 | * connection request from the server if it's not in the list.
|
---|
469 | *
|
---|
470 | * In SSH 2, each side of the connection minds its own business and
|
---|
471 | * doesn't send unnecessary information to the other. You arrange a
|
---|
472 | * remote forwarding by sending the server just the remote port
|
---|
473 | * number. When a connection comes in, the server tells you which
|
---|
474 | * of its ports was connected to; and _you_ have to remember what
|
---|
475 | * local host:port pair went with that port number.
|
---|
476 | *
|
---|
477 | * Hence: in SSH 1 this structure stores host:port pairs we intend
|
---|
478 | * to allow connections to, and is indexed by those host:port
|
---|
479 | * pairs. In SSH 2 it stores a mapping from source port to
|
---|
480 | * destination host:port pair, and is indexed by source port.
|
---|
481 | */
|
---|
482 | struct ssh_rportfwd {
|
---|
483 | unsigned sport, dport;
|
---|
484 | char dhost[256];
|
---|
485 | };
|
---|
486 |
|
---|
487 | struct Packet {
|
---|
488 | long length;
|
---|
489 | int type;
|
---|
490 | unsigned char *data;
|
---|
491 | unsigned char *body;
|
---|
492 | long savedpos;
|
---|
493 | long maxlen;
|
---|
494 | };
|
---|
495 |
|
---|
496 | static SHA_State exhash, exhashbase;
|
---|
497 |
|
---|
498 | static Socket s = NULL;
|
---|
499 |
|
---|
500 | static unsigned char session_key[32];
|
---|
501 | static int ssh1_compressing;
|
---|
502 | static int ssh1_remote_protoflags;
|
---|
503 | static int ssh1_local_protoflags;
|
---|
504 | static int ssh_agentfwd_enabled;
|
---|
505 | static int ssh_X11_fwd_enabled;
|
---|
506 | static int ssh_remote_bugs;
|
---|
507 | static const struct ssh_cipher *cipher = NULL;
|
---|
508 | static const struct ssh2_cipher *cscipher = NULL;
|
---|
509 | static const struct ssh2_cipher *sccipher = NULL;
|
---|
510 | static const struct ssh_mac *csmac = NULL;
|
---|
511 | static const struct ssh_mac *scmac = NULL;
|
---|
512 | static const struct ssh_compress *cscomp = NULL;
|
---|
513 | static const struct ssh_compress *sccomp = NULL;
|
---|
514 | static const struct ssh_kex *kex = NULL;
|
---|
515 | static const struct ssh_signkey *hostkey = NULL;
|
---|
516 | static unsigned char ssh2_session_id[20];
|
---|
517 |
|
---|
518 | static char *savedhost;
|
---|
519 | static int savedport;
|
---|
520 | static int ssh_send_ok;
|
---|
521 | static int ssh_echoing, ssh_editing;
|
---|
522 |
|
---|
523 | static tree234 *ssh_channels; /* indexed by local id */
|
---|
524 | static struct ssh_channel *mainchan; /* primary session channel */
|
---|
525 | static int ssh_exitcode = -1;
|
---|
526 |
|
---|
527 | static enum {
|
---|
528 | SSH_STATE_PREPACKET,
|
---|
529 | SSH_STATE_BEFORE_SIZE,
|
---|
530 | SSH_STATE_INTERMED,
|
---|
531 | SSH_STATE_SESSION,
|
---|
532 | SSH_STATE_CLOSED
|
---|
533 | } ssh_state = SSH_STATE_PREPACKET;
|
---|
534 |
|
---|
535 | static int size_needed = FALSE, eof_needed = FALSE;
|
---|
536 |
|
---|
537 | static struct Packet pktin = { 0, 0, NULL, NULL, 0 };
|
---|
538 | static struct Packet pktout = { 0, 0, NULL, NULL, 0 };
|
---|
539 | static unsigned char *deferred_send_data = NULL;
|
---|
540 | static int deferred_len = 0, deferred_size = 0;
|
---|
541 |
|
---|
542 | /*
|
---|
543 | * Gross hack: pscp will try to start SFTP but fall back to scp1 if
|
---|
544 | * that fails. This variable is the means by which scp.c can reach
|
---|
545 | * into the SSH code and find out which one it got.
|
---|
546 | */
|
---|
547 | int ssh_fallback_cmd = 0;
|
---|
548 |
|
---|
549 | static int ssh_version;
|
---|
550 | static int ssh1_throttle_count;
|
---|
551 | static int ssh_overall_bufsize;
|
---|
552 | static int ssh_throttled_all;
|
---|
553 | static int ssh1_stdout_throttling;
|
---|
554 | static void (*ssh_protocol) (unsigned char *in, int inlen, int ispkt);
|
---|
555 | static void ssh1_protocol(unsigned char *in, int inlen, int ispkt);
|
---|
556 | static void ssh2_protocol(unsigned char *in, int inlen, int ispkt);
|
---|
557 | static void ssh_size(void);
|
---|
558 | static void ssh_special(Telnet_Special);
|
---|
559 | static int ssh2_try_send(struct ssh_channel *c);
|
---|
560 | static void ssh2_add_channel_data(struct ssh_channel *c, char *buf,
|
---|
561 | int len);
|
---|
562 | static void ssh_throttle_all(int enable, int bufsize);
|
---|
563 | static void ssh2_set_window(struct ssh_channel *c, unsigned newwin);
|
---|
564 | static int (*s_rdpkt) (unsigned char **data, int *datalen);
|
---|
565 | static int ssh_sendbuffer(void);
|
---|
566 |
|
---|
567 | static struct rdpkt1_state_tag {
|
---|
568 | long len, pad, biglen, to_read;
|
---|
569 | unsigned long realcrc, gotcrc;
|
---|
570 | unsigned char *p;
|
---|
571 | int i;
|
---|
572 | int chunk;
|
---|
573 | } rdpkt1_state;
|
---|
574 |
|
---|
575 | static struct rdpkt2_state_tag {
|
---|
576 | long len, pad, payload, packetlen, maclen;
|
---|
577 | int i;
|
---|
578 | int cipherblk;
|
---|
579 | unsigned long incoming_sequence;
|
---|
580 | } rdpkt2_state;
|
---|
581 |
|
---|
582 | static int ssh_channelcmp(void *av, void *bv)
|
---|
583 | {
|
---|
584 | struct ssh_channel *a = (struct ssh_channel *) av;
|
---|
585 | struct ssh_channel *b = (struct ssh_channel *) bv;
|
---|
586 | if (a->localid < b->localid)
|
---|
587 | return -1;
|
---|
588 | if (a->localid > b->localid)
|
---|
589 | return +1;
|
---|
590 | return 0;
|
---|
591 | }
|
---|
592 | static int ssh_channelfind(void *av, void *bv)
|
---|
593 | {
|
---|
594 | unsigned *a = (unsigned *) av;
|
---|
595 | struct ssh_channel *b = (struct ssh_channel *) bv;
|
---|
596 | if (*a < b->localid)
|
---|
597 | return -1;
|
---|
598 | if (*a > b->localid)
|
---|
599 | return +1;
|
---|
600 | return 0;
|
---|
601 | }
|
---|
602 |
|
---|
603 | static int ssh_rportcmp_ssh1(void *av, void *bv)
|
---|
604 | {
|
---|
605 | struct ssh_rportfwd *a = (struct ssh_rportfwd *) av;
|
---|
606 | struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv;
|
---|
607 | int i;
|
---|
608 | if ( (i = strcmp(a->dhost, b->dhost)) != 0)
|
---|
609 | return i < 0 ? -1 : +1;
|
---|
610 | if (a->dport > b->dport)
|
---|
611 | return +1;
|
---|
612 | if (a->dport < b->dport)
|
---|
613 | return -1;
|
---|
614 | return 0;
|
---|
615 | }
|
---|
616 |
|
---|
617 | static int ssh_rportcmp_ssh2(void *av, void *bv)
|
---|
618 | {
|
---|
619 | struct ssh_rportfwd *a = (struct ssh_rportfwd *) av;
|
---|
620 | struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv;
|
---|
621 |
|
---|
622 | if (a->sport > b->sport)
|
---|
623 | return +1;
|
---|
624 | if (a->sport < b->sport)
|
---|
625 | return -1;
|
---|
626 | return 0;
|
---|
627 | }
|
---|
628 |
|
---|
629 | static int alloc_channel_id(void)
|
---|
630 | {
|
---|
631 | const unsigned CHANNEL_NUMBER_OFFSET = 256;
|
---|
632 | unsigned low, high, mid;
|
---|
633 | int tsize;
|
---|
634 | struct ssh_channel *c;
|
---|
635 |
|
---|
636 | /*
|
---|
637 | * First-fit allocation of channel numbers: always pick the
|
---|
638 | * lowest unused one. To do this, binary-search using the
|
---|
639 | * counted B-tree to find the largest channel ID which is in a
|
---|
640 | * contiguous sequence from the beginning. (Precisely
|
---|
641 | * everything in that sequence must have ID equal to its tree
|
---|
642 | * index plus CHANNEL_NUMBER_OFFSET.)
|
---|
643 | */
|
---|
644 | tsize = count234(ssh_channels);
|
---|
645 |
|
---|
646 | low = -1;
|
---|
647 | high = tsize;
|
---|
648 | while (high - low > 1) {
|
---|
649 | mid = (high + low) / 2;
|
---|
650 | c = index234(ssh_channels, mid);
|
---|
651 | if (c->localid == mid + CHANNEL_NUMBER_OFFSET)
|
---|
652 | low = mid; /* this one is fine */
|
---|
653 | else
|
---|
654 | high = mid; /* this one is past it */
|
---|
655 | }
|
---|
656 | /*
|
---|
657 | * Now low points to either -1, or the tree index of the
|
---|
658 | * largest ID in the initial sequence.
|
---|
659 | */
|
---|
660 | {
|
---|
661 | unsigned i = low + 1 + CHANNEL_NUMBER_OFFSET;
|
---|
662 | assert(NULL == find234(ssh_channels, &i, ssh_channelfind));
|
---|
663 | }
|
---|
664 | return low + 1 + CHANNEL_NUMBER_OFFSET;
|
---|
665 | }
|
---|
666 |
|
---|
667 | static void c_write(char *buf, int len)
|
---|
668 | {
|
---|
669 | if ((flags & FLAG_STDERR)) {
|
---|
670 | int i;
|
---|
671 | for (i = 0; i < len; i++)
|
---|
672 | if (buf[i] != '\r')
|
---|
673 | fputc(buf[i], stderr);
|
---|
674 | return;
|
---|
675 | }
|
---|
676 | from_backend(1, buf, len);
|
---|
677 | }
|
---|
678 |
|
---|
679 | static void c_write_untrusted(char *buf, int len)
|
---|
680 | {
|
---|
681 | int i;
|
---|
682 | for (i = 0; i < len; i++) {
|
---|
683 | if (buf[i] == '\n')
|
---|
684 | c_write("\r\n", 2);
|
---|
685 | else if ((buf[i] & 0x60) || (buf[i] == '\r'))
|
---|
686 | c_write(buf + i, 1);
|
---|
687 | }
|
---|
688 | }
|
---|
689 |
|
---|
690 | static void c_write_str(char *buf)
|
---|
691 | {
|
---|
692 | c_write(buf, strlen(buf));
|
---|
693 | }
|
---|
694 |
|
---|
695 | /*
|
---|
696 | * Collect incoming data in the incoming packet buffer.
|
---|
697 | * Decipher and verify the packet when it is completely read.
|
---|
698 | * Drop SSH1_MSG_DEBUG and SSH1_MSG_IGNORE packets.
|
---|
699 | * Update the *data and *datalen variables.
|
---|
700 | * Return the additional nr of bytes needed, or 0 when
|
---|
701 | * a complete packet is available.
|
---|
702 | */
|
---|
703 | static int ssh1_rdpkt(unsigned char **data, int *datalen)
|
---|
704 | {
|
---|
705 | struct rdpkt1_state_tag *st = &rdpkt1_state;
|
---|
706 |
|
---|
707 | crBegin;
|
---|
708 |
|
---|
709 | next_packet:
|
---|
710 |
|
---|
711 | pktin.type = 0;
|
---|
712 | pktin.length = 0;
|
---|
713 |
|
---|
714 | for (st->i = st->len = 0; st->i < 4; st->i++) {
|
---|
715 | while ((*datalen) == 0)
|
---|
716 | crReturn(4 - st->i);
|
---|
717 | st->len = (st->len << 8) + **data;
|
---|
718 | (*data)++, (*datalen)--;
|
---|
719 | }
|
---|
720 |
|
---|
721 | st->pad = 8 - (st->len % 8);
|
---|
722 | st->biglen = st->len + st->pad;
|
---|
723 | pktin.length = st->len - 5;
|
---|
724 |
|
---|
725 | if (pktin.maxlen < st->biglen) {
|
---|
726 | pktin.maxlen = st->biglen;
|
---|
727 | pktin.data = (pktin.data == NULL ? smalloc(st->biglen + APIEXTRA) :
|
---|
728 | srealloc(pktin.data, st->biglen + APIEXTRA));
|
---|
729 | if (!pktin.data)
|
---|
730 | fatalbox("Out of memory");
|
---|
731 | }
|
---|
732 |
|
---|
733 | st->to_read = st->biglen;
|
---|
734 | st->p = pktin.data;
|
---|
735 | while (st->to_read > 0) {
|
---|
736 | st->chunk = st->to_read;
|
---|
737 | while ((*datalen) == 0)
|
---|
738 | crReturn(st->to_read);
|
---|
739 | if (st->chunk > (*datalen))
|
---|
740 | st->chunk = (*datalen);
|
---|
741 | memcpy(st->p, *data, st->chunk);
|
---|
742 | *data += st->chunk;
|
---|
743 | *datalen -= st->chunk;
|
---|
744 | st->p += st->chunk;
|
---|
745 | st->to_read -= st->chunk;
|
---|
746 | }
|
---|
747 |
|
---|
748 | if (cipher && detect_attack(pktin.data, st->biglen, NULL)) {
|
---|
749 | bombout(("Network attack (CRC compensation) detected!"));
|
---|
750 | crReturn(0);
|
---|
751 | }
|
---|
752 |
|
---|
753 | if (cipher)
|
---|
754 | cipher->decrypt(pktin.data, st->biglen);
|
---|
755 |
|
---|
756 | st->realcrc = crc32(pktin.data, st->biglen - 4);
|
---|
757 | st->gotcrc = GET_32BIT(pktin.data + st->biglen - 4);
|
---|
758 | if (st->gotcrc != st->realcrc) {
|
---|
759 | bombout(("Incorrect CRC received on packet"));
|
---|
760 | crReturn(0);
|
---|
761 | }
|
---|
762 |
|
---|
763 | pktin.body = pktin.data + st->pad + 1;
|
---|
764 |
|
---|
765 | if (ssh1_compressing) {
|
---|
766 | unsigned char *decompblk;
|
---|
767 | int decomplen;
|
---|
768 | zlib_decompress_block(pktin.body - 1, pktin.length + 1,
|
---|
769 | &decompblk, &decomplen);
|
---|
770 |
|
---|
771 | if (pktin.maxlen < st->pad + decomplen) {
|
---|
772 | pktin.maxlen = st->pad + decomplen;
|
---|
773 | pktin.data = srealloc(pktin.data, pktin.maxlen + APIEXTRA);
|
---|
774 | pktin.body = pktin.data + st->pad + 1;
|
---|
775 | if (!pktin.data)
|
---|
776 | fatalbox("Out of memory");
|
---|
777 | }
|
---|
778 |
|
---|
779 | memcpy(pktin.body - 1, decompblk, decomplen);
|
---|
780 | sfree(decompblk);
|
---|
781 | pktin.length = decomplen - 1;
|
---|
782 | }
|
---|
783 |
|
---|
784 | pktin.type = pktin.body[-1];
|
---|
785 |
|
---|
786 | // log_packet(PKT_INCOMING, pktin.type, ssh1_pkt_type(pktin.type),
|
---|
787 | // pktin.body, pktin.length);
|
---|
788 |
|
---|
789 | if (pktin.type == SSH1_SMSG_STDOUT_DATA ||
|
---|
790 | pktin.type == SSH1_SMSG_STDERR_DATA ||
|
---|
791 | pktin.type == SSH1_MSG_DEBUG ||
|
---|
792 | pktin.type == SSH1_SMSG_AUTH_TIS_CHALLENGE ||
|
---|
793 | pktin.type == SSH1_SMSG_AUTH_CCARD_CHALLENGE) {
|
---|
794 | long stringlen = GET_32BIT(pktin.body);
|
---|
795 | if (stringlen + 4 != pktin.length) {
|
---|
796 | bombout(("Received data packet with bogus string length"));
|
---|
797 | crReturn(0);
|
---|
798 | }
|
---|
799 | }
|
---|
800 |
|
---|
801 | if (pktin.type == SSH1_MSG_DEBUG) {
|
---|
802 | /* log debug message */
|
---|
803 | char buf[80];
|
---|
804 | int stringlen = GET_32BIT(pktin.body);
|
---|
805 | strcpy(buf, "Remote: ");
|
---|
806 | if (stringlen > 70)
|
---|
807 | stringlen = 70;
|
---|
808 | memcpy(buf + 8, pktin.body + 4, stringlen);
|
---|
809 | buf[8 + stringlen] = '\0';
|
---|
810 | logevent(buf);
|
---|
811 | goto next_packet;
|
---|
812 | } else if (pktin.type == SSH1_MSG_IGNORE) {
|
---|
813 | /* do nothing */
|
---|
814 | goto next_packet;
|
---|
815 | }
|
---|
816 |
|
---|
817 | if (pktin.type == SSH1_MSG_DISCONNECT) {
|
---|
818 | /* log reason code in disconnect message */
|
---|
819 | char buf[256];
|
---|
820 | unsigned msglen = GET_32BIT(pktin.body);
|
---|
821 | unsigned nowlen;
|
---|
822 | strcpy(buf, "Remote sent disconnect: ");
|
---|
823 | nowlen = strlen(buf);
|
---|
824 | if (msglen > sizeof(buf) - nowlen - 1)
|
---|
825 | msglen = sizeof(buf) - nowlen - 1;
|
---|
826 | memcpy(buf + nowlen, pktin.body + 4, msglen);
|
---|
827 | buf[nowlen + msglen] = '\0';
|
---|
828 | bombout(("Server sent disconnect message:\n\"%s\"", buf+nowlen));
|
---|
829 | crReturn(0);
|
---|
830 | }
|
---|
831 |
|
---|
832 | crFinish(0);
|
---|
833 | }
|
---|
834 |
|
---|
835 | static int ssh2_rdpkt(unsigned char **data, int *datalen)
|
---|
836 | {
|
---|
837 | struct rdpkt2_state_tag *st = &rdpkt2_state;
|
---|
838 |
|
---|
839 | crBegin;
|
---|
840 |
|
---|
841 | next_packet:
|
---|
842 | pktin.type = 0;
|
---|
843 | pktin.length = 0;
|
---|
844 | if (sccipher)
|
---|
845 | st->cipherblk = sccipher->blksize;
|
---|
846 | else
|
---|
847 | st->cipherblk = 8;
|
---|
848 | if (st->cipherblk < 8)
|
---|
849 | st->cipherblk = 8;
|
---|
850 |
|
---|
851 | if (pktin.maxlen < st->cipherblk) {
|
---|
852 | pktin.maxlen = st->cipherblk;
|
---|
853 | pktin.data =
|
---|
854 | (pktin.data ==
|
---|
855 | NULL ? smalloc(st->cipherblk +
|
---|
856 | APIEXTRA) : srealloc(pktin.data,
|
---|
857 | st->cipherblk +
|
---|
858 | APIEXTRA));
|
---|
859 | if (!pktin.data)
|
---|
860 | fatalbox("Out of memory");
|
---|
861 | }
|
---|
862 |
|
---|
863 | /*
|
---|
864 | * Acquire and decrypt the first block of the packet. This will
|
---|
865 | * contain the length and padding details.
|
---|
866 | */
|
---|
867 | for (st->i = st->len = 0; st->i < st->cipherblk; st->i++) {
|
---|
868 | while ((*datalen) == 0)
|
---|
869 | crReturn(st->cipherblk - st->i);
|
---|
870 | pktin.data[st->i] = *(*data)++;
|
---|
871 | (*datalen)--;
|
---|
872 | }
|
---|
873 |
|
---|
874 | if (sccipher)
|
---|
875 | sccipher->decrypt(pktin.data, st->cipherblk);
|
---|
876 |
|
---|
877 | /*
|
---|
878 | * _Completely_ silly lengths should be stomped on before they
|
---|
879 | * do us any more damage
|
---|
880 | */
|
---|
881 | if (st->len < 0 || st->pad < 0 || st->len + st->pad <0) {
|
---|
882 | bombout(("Incoming packet was garbled on decryption"));
|
---|
883 | crReturn(0);
|
---|
884 | }
|
---|
885 |
|
---|
886 | /*
|
---|
887 | * Now get the length and padding figures.
|
---|
888 | */
|
---|
889 | st->len = GET_32BIT(pktin.data);
|
---|
890 | st->pad = pktin.data[4];
|
---|
891 |
|
---|
892 | /*
|
---|
893 | * This enables us to deduce the payload length.
|
---|
894 | */
|
---|
895 | st->payload = st->len - st->pad - 1;
|
---|
896 |
|
---|
897 | pktin.length = st->payload + 5;
|
---|
898 |
|
---|
899 | /*
|
---|
900 | * So now we can work out the total packet length.
|
---|
901 | */
|
---|
902 | st->packetlen = st->len + 4;
|
---|
903 | st->maclen = scmac ? scmac->len : 0;
|
---|
904 |
|
---|
905 | /*
|
---|
906 | * Adjust memory allocation if packet is too big.
|
---|
907 | */
|
---|
908 | if (pktin.maxlen < st->packetlen + st->maclen) {
|
---|
909 | pktin.maxlen = st->packetlen + st->maclen;
|
---|
910 | pktin.data =
|
---|
911 | (pktin.data ==
|
---|
912 | NULL ? smalloc(pktin.maxlen + APIEXTRA) : srealloc(pktin.data,
|
---|
913 | pktin.maxlen
|
---|
914 | +
|
---|
915 | APIEXTRA));
|
---|
916 | if (!pktin.data)
|
---|
917 | fatalbox("Out of memory");
|
---|
918 | }
|
---|
919 |
|
---|
920 | /*
|
---|
921 | * Read and decrypt the remainder of the packet.
|
---|
922 | */
|
---|
923 | for (st->i = st->cipherblk; st->i < st->packetlen + st->maclen;
|
---|
924 | st->i++) {
|
---|
925 | while ((*datalen) == 0)
|
---|
926 | crReturn(st->packetlen + st->maclen - st->i);
|
---|
927 | pktin.data[st->i] = *(*data)++;
|
---|
928 | (*datalen)--;
|
---|
929 | }
|
---|
930 | /* Decrypt everything _except_ the MAC. */
|
---|
931 | if (sccipher)
|
---|
932 | sccipher->decrypt(pktin.data + st->cipherblk,
|
---|
933 | st->packetlen - st->cipherblk);
|
---|
934 |
|
---|
935 | /*
|
---|
936 | * Check the MAC.
|
---|
937 | */
|
---|
938 | if (scmac
|
---|
939 | && !scmac->verify(pktin.data, st->len + 4,
|
---|
940 | st->incoming_sequence)) {
|
---|
941 | bombout(("Incorrect MAC received on packet"));
|
---|
942 | crReturn(0);
|
---|
943 | }
|
---|
944 | st->incoming_sequence++; /* whether or not we MACed */
|
---|
945 |
|
---|
946 | /*
|
---|
947 | * Decompress packet payload.
|
---|
948 | */
|
---|
949 | {
|
---|
950 | unsigned char *newpayload;
|
---|
951 | int newlen;
|
---|
952 | if (sccomp && sccomp->decompress(pktin.data + 5, pktin.length - 5,
|
---|
953 | &newpayload, &newlen)) {
|
---|
954 | if (pktin.maxlen < newlen + 5) {
|
---|
955 | pktin.maxlen = newlen + 5;
|
---|
956 | pktin.data =
|
---|
957 | (pktin.data ==
|
---|
958 | NULL ? smalloc(pktin.maxlen +
|
---|
959 | APIEXTRA) : srealloc(pktin.data,
|
---|
960 | pktin.maxlen +
|
---|
961 | APIEXTRA));
|
---|
962 | if (!pktin.data)
|
---|
963 | fatalbox("Out of memory");
|
---|
964 | }
|
---|
965 | pktin.length = 5 + newlen;
|
---|
966 | memcpy(pktin.data + 5, newpayload, newlen);
|
---|
967 | sfree(newpayload);
|
---|
968 | }
|
---|
969 | }
|
---|
970 |
|
---|
971 | pktin.savedpos = 6;
|
---|
972 | pktin.type = pktin.data[5];
|
---|
973 |
|
---|
974 | // log_packet(PKT_INCOMING, pktin.type, ssh2_pkt_type(pktin.type),
|
---|
975 | // pktin.data+6, pktin.length-6);
|
---|
976 |
|
---|
977 | switch (pktin.type) {
|
---|
978 | /*
|
---|
979 | * These packets we must handle instantly.
|
---|
980 | */
|
---|
981 | case SSH2_MSG_DISCONNECT:
|
---|
982 | {
|
---|
983 | /* log reason code in disconnect message */
|
---|
984 | char buf[256];
|
---|
985 | int reason = GET_32BIT(pktin.data + 6);
|
---|
986 | unsigned msglen = GET_32BIT(pktin.data + 10);
|
---|
987 | unsigned nowlen;
|
---|
988 | if (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) {
|
---|
989 | sprintf(buf, "Received disconnect message (%s)",
|
---|
990 | ssh2_disconnect_reasons[reason]);
|
---|
991 | } else {
|
---|
992 | sprintf(buf, "Received disconnect message (unknown type %d)",
|
---|
993 | reason);
|
---|
994 | }
|
---|
995 | logevent(buf);
|
---|
996 | strcpy(buf, "Disconnection message text: ");
|
---|
997 | nowlen = strlen(buf);
|
---|
998 | if (msglen > sizeof(buf) - nowlen - 1)
|
---|
999 | msglen = sizeof(buf) - nowlen - 1;
|
---|
1000 | memcpy(buf + nowlen, pktin.data + 14, msglen);
|
---|
1001 | buf[nowlen + msglen] = '\0';
|
---|
1002 | logevent(buf);
|
---|
1003 | bombout(("Server sent disconnect message\ntype %d (%s):\n\"%s\"",
|
---|
1004 | reason,
|
---|
1005 | (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) ?
|
---|
1006 | ssh2_disconnect_reasons[reason] : "unknown",
|
---|
1007 | buf+nowlen));
|
---|
1008 | crReturn(0);
|
---|
1009 | }
|
---|
1010 | break;
|
---|
1011 | case SSH2_MSG_IGNORE:
|
---|
1012 | goto next_packet;
|
---|
1013 | case SSH2_MSG_DEBUG:
|
---|
1014 | {
|
---|
1015 | /* log the debug message */
|
---|
1016 | char buf[512];
|
---|
1017 | /* int display = pktin.body[6]; */
|
---|
1018 | int stringlen = GET_32BIT(pktin.data+7);
|
---|
1019 | int prefix;
|
---|
1020 | strcpy(buf, "Remote debug message: ");
|
---|
1021 | prefix = strlen(buf);
|
---|
1022 | if (stringlen > (int)sizeof(buf)-prefix-1)
|
---|
1023 | stringlen = sizeof(buf)-prefix-1;
|
---|
1024 | memcpy(buf + prefix, pktin.data + 11, stringlen);
|
---|
1025 | buf[prefix + stringlen] = '\0';
|
---|
1026 | logevent(buf);
|
---|
1027 | }
|
---|
1028 | goto next_packet; /* FIXME: print the debug message */
|
---|
1029 |
|
---|
1030 | /*
|
---|
1031 | * These packets we need do nothing about here.
|
---|
1032 | */
|
---|
1033 | case SSH2_MSG_UNIMPLEMENTED:
|
---|
1034 | case SSH2_MSG_SERVICE_REQUEST:
|
---|
1035 | case SSH2_MSG_SERVICE_ACCEPT:
|
---|
1036 | case SSH2_MSG_KEXINIT:
|
---|
1037 | case SSH2_MSG_NEWKEYS:
|
---|
1038 | case SSH2_MSG_KEXDH_INIT:
|
---|
1039 | case SSH2_MSG_KEXDH_REPLY:
|
---|
1040 | /* case SSH2_MSG_KEX_DH_GEX_REQUEST: duplicate case value */
|
---|
1041 | /* case SSH2_MSG_KEX_DH_GEX_GROUP: duplicate case value */
|
---|
1042 | case SSH2_MSG_KEX_DH_GEX_INIT:
|
---|
1043 | case SSH2_MSG_KEX_DH_GEX_REPLY:
|
---|
1044 | case SSH2_MSG_USERAUTH_REQUEST:
|
---|
1045 | case SSH2_MSG_USERAUTH_FAILURE:
|
---|
1046 | case SSH2_MSG_USERAUTH_SUCCESS:
|
---|
1047 | case SSH2_MSG_USERAUTH_BANNER:
|
---|
1048 | case SSH2_MSG_USERAUTH_PK_OK:
|
---|
1049 | /* case SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: duplicate case value */
|
---|
1050 | /* case SSH2_MSG_USERAUTH_INFO_REQUEST: duplicate case value */
|
---|
1051 | case SSH2_MSG_USERAUTH_INFO_RESPONSE:
|
---|
1052 | case SSH2_MSG_GLOBAL_REQUEST:
|
---|
1053 | case SSH2_MSG_REQUEST_SUCCESS:
|
---|
1054 | case SSH2_MSG_REQUEST_FAILURE:
|
---|
1055 | case SSH2_MSG_CHANNEL_OPEN:
|
---|
1056 | case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
|
---|
1057 | case SSH2_MSG_CHANNEL_OPEN_FAILURE:
|
---|
1058 | case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
|
---|
1059 | case SSH2_MSG_CHANNEL_DATA:
|
---|
1060 | case SSH2_MSG_CHANNEL_EXTENDED_DATA:
|
---|
1061 | case SSH2_MSG_CHANNEL_EOF:
|
---|
1062 | case SSH2_MSG_CHANNEL_CLOSE:
|
---|
1063 | case SSH2_MSG_CHANNEL_REQUEST:
|
---|
1064 | case SSH2_MSG_CHANNEL_SUCCESS:
|
---|
1065 | case SSH2_MSG_CHANNEL_FAILURE:
|
---|
1066 | break;
|
---|
1067 |
|
---|
1068 | /*
|
---|
1069 | * For anything else we send SSH2_MSG_UNIMPLEMENTED.
|
---|
1070 | */
|
---|
1071 | default:
|
---|
1072 | ssh2_pkt_init(SSH2_MSG_UNIMPLEMENTED);
|
---|
1073 | ssh2_pkt_adduint32(st->incoming_sequence - 1);
|
---|
1074 | ssh2_pkt_send();
|
---|
1075 | break;
|
---|
1076 | }
|
---|
1077 |
|
---|
1078 | crFinish(0);
|
---|
1079 | }
|
---|
1080 |
|
---|
1081 | static void ssh1_pktout_size(int len)
|
---|
1082 | {
|
---|
1083 | int pad, biglen;
|
---|
1084 |
|
---|
1085 | len += 5; /* type and CRC */
|
---|
1086 | pad = 8 - (len % 8);
|
---|
1087 | biglen = len + pad;
|
---|
1088 |
|
---|
1089 | pktout.length = len - 5;
|
---|
1090 | if (pktout.maxlen < biglen) {
|
---|
1091 | pktout.maxlen = biglen;
|
---|
1092 | #ifdef MSCRYPTOAPI
|
---|
1093 | /* Allocate enough buffer space for extra block
|
---|
1094 | * for MS CryptEncrypt() */
|
---|
1095 | pktout.data = (pktout.data == NULL ? smalloc(biglen + 12) :
|
---|
1096 | srealloc(pktout.data, biglen + 12));
|
---|
1097 | #else
|
---|
1098 | pktout.data = (pktout.data == NULL ? smalloc(biglen + 4) :
|
---|
1099 | srealloc(pktout.data, biglen + 4));
|
---|
1100 | #endif
|
---|
1101 | if (!pktout.data)
|
---|
1102 | fatalbox("Out of memory");
|
---|
1103 | }
|
---|
1104 | pktout.body = pktout.data + 4 + pad + 1;
|
---|
1105 | }
|
---|
1106 |
|
---|
1107 | static void s_wrpkt_start(int type, int len)
|
---|
1108 | {
|
---|
1109 | ssh1_pktout_size(len);
|
---|
1110 | pktout.type = type;
|
---|
1111 | }
|
---|
1112 |
|
---|
1113 | static int s_wrpkt_prepare(void)
|
---|
1114 | {
|
---|
1115 | int pad, len, biglen, i;
|
---|
1116 | unsigned long crc;
|
---|
1117 |
|
---|
1118 | pktout.body[-1] = pktout.type;
|
---|
1119 |
|
---|
1120 | // log_packet(PKT_OUTGOING, pktout.type, ssh1_pkt_type(pktout.type),
|
---|
1121 | // pktout.body, pktout.length);
|
---|
1122 |
|
---|
1123 | if (ssh1_compressing) {
|
---|
1124 | unsigned char *compblk;
|
---|
1125 | int complen;
|
---|
1126 | zlib_compress_block(pktout.body - 1, pktout.length + 1,
|
---|
1127 | &compblk, &complen);
|
---|
1128 | ssh1_pktout_size(complen - 1);
|
---|
1129 | memcpy(pktout.body - 1, compblk, complen);
|
---|
1130 | sfree(compblk);
|
---|
1131 | }
|
---|
1132 |
|
---|
1133 | len = pktout.length + 5; /* type and CRC */
|
---|
1134 | pad = 8 - (len % 8);
|
---|
1135 | biglen = len + pad;
|
---|
1136 |
|
---|
1137 | for (i = 0; i < pad; i++)
|
---|
1138 | pktout.data[i + 4] = random_byte();
|
---|
1139 | crc = crc32(pktout.data + 4, biglen - 4);
|
---|
1140 | PUT_32BIT(pktout.data + biglen, crc);
|
---|
1141 | PUT_32BIT(pktout.data, len);
|
---|
1142 |
|
---|
1143 | if (cipher)
|
---|
1144 | cipher->encrypt(pktout.data + 4, biglen);
|
---|
1145 |
|
---|
1146 | return biglen + 4;
|
---|
1147 | }
|
---|
1148 |
|
---|
1149 | static void s_wrpkt(void)
|
---|
1150 | {
|
---|
1151 | int len, backlog;
|
---|
1152 | len = s_wrpkt_prepare();
|
---|
1153 | backlog = sk_write(s, pktout.data, len);
|
---|
1154 | if (backlog > SSH_MAX_BACKLOG)
|
---|
1155 | ssh_throttle_all(1, backlog);
|
---|
1156 | }
|
---|
1157 |
|
---|
1158 | static void s_wrpkt_defer(void)
|
---|
1159 | {
|
---|
1160 | int len;
|
---|
1161 | len = s_wrpkt_prepare();
|
---|
1162 | if (deferred_len + len > deferred_size) {
|
---|
1163 | deferred_size = deferred_len + len + 128;
|
---|
1164 | deferred_send_data = srealloc(deferred_send_data, deferred_size);
|
---|
1165 | }
|
---|
1166 | memcpy(deferred_send_data + deferred_len, pktout.data, len);
|
---|
1167 | deferred_len += len;
|
---|
1168 | }
|
---|
1169 |
|
---|
1170 | /*
|
---|
1171 | * Construct a packet with the specified contents.
|
---|
1172 | */
|
---|
1173 | static void construct_packet(int pkttype, va_list ap1, va_list ap2)
|
---|
1174 | {
|
---|
1175 | unsigned char *p, *argp, argchar;
|
---|
1176 | unsigned long argint;
|
---|
1177 | int pktlen, argtype, arglen;
|
---|
1178 | Bignum bn;
|
---|
1179 |
|
---|
1180 | pktlen = 0;
|
---|
1181 | while ((argtype = va_arg(ap1, int)) != PKT_END) {
|
---|
1182 | switch (argtype) {
|
---|
1183 | case PKT_INT:
|
---|
1184 | (void) va_arg(ap1, int);
|
---|
1185 | pktlen += 4;
|
---|
1186 | break;
|
---|
1187 | case PKT_CHAR:
|
---|
1188 | (void) va_arg(ap1, char);
|
---|
1189 | pktlen++;
|
---|
1190 | break;
|
---|
1191 | case PKT_DATA:
|
---|
1192 | (void) va_arg(ap1, unsigned char *);
|
---|
1193 | arglen = va_arg(ap1, int);
|
---|
1194 | pktlen += arglen;
|
---|
1195 | break;
|
---|
1196 | case PKT_STR:
|
---|
1197 | argp = va_arg(ap1, unsigned char *);
|
---|
1198 | arglen = strlen(argp);
|
---|
1199 | pktlen += 4 + arglen;
|
---|
1200 | break;
|
---|
1201 | case PKT_BIGNUM:
|
---|
1202 | bn = va_arg(ap1, Bignum);
|
---|
1203 | pktlen += ssh1_bignum_length(bn);
|
---|
1204 | break;
|
---|
1205 | default:
|
---|
1206 | assert(0);
|
---|
1207 | }
|
---|
1208 | }
|
---|
1209 |
|
---|
1210 | s_wrpkt_start(pkttype, pktlen);
|
---|
1211 | p = pktout.body;
|
---|
1212 |
|
---|
1213 | while ((argtype = va_arg(ap2, int)) != PKT_END) {
|
---|
1214 | switch (argtype) {
|
---|
1215 | case PKT_INT:
|
---|
1216 | argint = va_arg(ap2, int);
|
---|
1217 | PUT_32BIT(p, argint);
|
---|
1218 | p += 4;
|
---|
1219 | break;
|
---|
1220 | case PKT_CHAR:
|
---|
1221 | argchar = va_arg(ap2, unsigned char);
|
---|
1222 | *p = argchar;
|
---|
1223 | p++;
|
---|
1224 | break;
|
---|
1225 | case PKT_DATA:
|
---|
1226 | argp = va_arg(ap2, unsigned char *);
|
---|
1227 | arglen = va_arg(ap2, int);
|
---|
1228 | memcpy(p, argp, arglen);
|
---|
1229 | p += arglen;
|
---|
1230 | break;
|
---|
1231 | case PKT_STR:
|
---|
1232 | argp = va_arg(ap2, unsigned char *);
|
---|
1233 | arglen = strlen(argp);
|
---|
1234 | PUT_32BIT(p, arglen);
|
---|
1235 | memcpy(p + 4, argp, arglen);
|
---|
1236 | p += 4 + arglen;
|
---|
1237 | break;
|
---|
1238 | case PKT_BIGNUM:
|
---|
1239 | bn = va_arg(ap2, Bignum);
|
---|
1240 | p += ssh1_write_bignum(p, bn);
|
---|
1241 | break;
|
---|
1242 | }
|
---|
1243 | }
|
---|
1244 | }
|
---|
1245 |
|
---|
1246 | static void send_packet(int pkttype, ...)
|
---|
1247 | {
|
---|
1248 | va_list ap1, ap2;
|
---|
1249 | va_start(ap1, pkttype);
|
---|
1250 | va_start(ap2, pkttype);
|
---|
1251 | construct_packet(pkttype, ap1, ap2);
|
---|
1252 | s_wrpkt();
|
---|
1253 | }
|
---|
1254 |
|
---|
1255 | static void defer_packet(int pkttype, ...)
|
---|
1256 | {
|
---|
1257 | va_list ap1, ap2;
|
---|
1258 | va_start(ap1, pkttype);
|
---|
1259 | va_start(ap2, pkttype);
|
---|
1260 | construct_packet(pkttype, ap1, ap2);
|
---|
1261 | s_wrpkt_defer();
|
---|
1262 | }
|
---|
1263 |
|
---|
1264 | static int ssh_versioncmp(char *a, char *b)
|
---|
1265 | {
|
---|
1266 | char *ae, *be;
|
---|
1267 | unsigned long av, bv;
|
---|
1268 |
|
---|
1269 | av = strtoul(a, &ae, 10);
|
---|
1270 | bv = strtoul(b, &be, 10);
|
---|
1271 | if (av != bv)
|
---|
1272 | return (av < bv ? -1 : +1);
|
---|
1273 | if (*ae == '.')
|
---|
1274 | ae++;
|
---|
1275 | if (*be == '.')
|
---|
1276 | be++;
|
---|
1277 | av = strtoul(ae, &ae, 10);
|
---|
1278 | bv = strtoul(be, &be, 10);
|
---|
1279 | if (av != bv)
|
---|
1280 | return (av < bv ? -1 : +1);
|
---|
1281 | return 0;
|
---|
1282 | }
|
---|
1283 |
|
---|
1284 |
|
---|
1285 | /*
|
---|
1286 | * Utility routines for putting an SSH-protocol `string' and
|
---|
1287 | * `uint32' into a SHA state.
|
---|
1288 | */
|
---|
1289 | #include <stdio.h>
|
---|
1290 | static void sha_string(SHA_State * s, void *str, int len)
|
---|
1291 | {
|
---|
1292 | unsigned char lenblk[4];
|
---|
1293 | PUT_32BIT(lenblk, len);
|
---|
1294 | SHA_Bytes(s, lenblk, 4);
|
---|
1295 | SHA_Bytes(s, str, len);
|
---|
1296 | }
|
---|
1297 |
|
---|
1298 | static void sha_uint32(SHA_State * s, unsigned i)
|
---|
1299 | {
|
---|
1300 | unsigned char intblk[4];
|
---|
1301 | PUT_32BIT(intblk, i);
|
---|
1302 | SHA_Bytes(s, intblk, 4);
|
---|
1303 | }
|
---|
1304 |
|
---|
1305 | /*
|
---|
1306 | * SSH2 packet construction functions.
|
---|
1307 | */
|
---|
1308 | static void ssh2_pkt_ensure(int length)
|
---|
1309 | {
|
---|
1310 | if (pktout.maxlen < length) {
|
---|
1311 | pktout.maxlen = length + 256;
|
---|
1312 | pktout.data =
|
---|
1313 | (pktout.data ==
|
---|
1314 | NULL ? smalloc(pktout.maxlen +
|
---|
1315 | APIEXTRA) : srealloc(pktout.data,
|
---|
1316 | pktout.maxlen +
|
---|
1317 | APIEXTRA));
|
---|
1318 | if (!pktout.data)
|
---|
1319 | fatalbox("Out of memory");
|
---|
1320 | }
|
---|
1321 | }
|
---|
1322 | static void ssh2_pkt_adddata(void *data, int len)
|
---|
1323 | {
|
---|
1324 | pktout.length += len;
|
---|
1325 | ssh2_pkt_ensure(pktout.length);
|
---|
1326 | memcpy(pktout.data + pktout.length - len, data, len);
|
---|
1327 | }
|
---|
1328 | static void ssh2_pkt_addbyte(unsigned char byte)
|
---|
1329 | {
|
---|
1330 | ssh2_pkt_adddata(&byte, 1);
|
---|
1331 | }
|
---|
1332 | static void ssh2_pkt_init(int pkt_type)
|
---|
1333 | {
|
---|
1334 | pktout.length = 5;
|
---|
1335 | ssh2_pkt_addbyte((unsigned char) pkt_type);
|
---|
1336 | }
|
---|
1337 | static void ssh2_pkt_addbool(unsigned char value)
|
---|
1338 | {
|
---|
1339 | ssh2_pkt_adddata(&value, 1);
|
---|
1340 | }
|
---|
1341 | static void ssh2_pkt_adduint32(unsigned long value)
|
---|
1342 | {
|
---|
1343 | unsigned char x[4];
|
---|
1344 | PUT_32BIT(x, value);
|
---|
1345 | ssh2_pkt_adddata(x, 4);
|
---|
1346 | }
|
---|
1347 | static void ssh2_pkt_addstring_start(void)
|
---|
1348 | {
|
---|
1349 | ssh2_pkt_adduint32(0);
|
---|
1350 | pktout.savedpos = pktout.length;
|
---|
1351 | }
|
---|
1352 | static void ssh2_pkt_addstring_str(char *data)
|
---|
1353 | {
|
---|
1354 | ssh2_pkt_adddata(data, strlen(data));
|
---|
1355 | PUT_32BIT(pktout.data + pktout.savedpos - 4,
|
---|
1356 | pktout.length - pktout.savedpos);
|
---|
1357 | }
|
---|
1358 | static void ssh2_pkt_addstring_data(char *data, int len)
|
---|
1359 | {
|
---|
1360 | ssh2_pkt_adddata(data, len);
|
---|
1361 | PUT_32BIT(pktout.data + pktout.savedpos - 4,
|
---|
1362 | pktout.length - pktout.savedpos);
|
---|
1363 | }
|
---|
1364 | static void ssh2_pkt_addstring(char *data)
|
---|
1365 | {
|
---|
1366 | ssh2_pkt_addstring_start();
|
---|
1367 | ssh2_pkt_addstring_str(data);
|
---|
1368 | }
|
---|
1369 | static char *ssh2_mpint_fmt(Bignum b, int *len)
|
---|
1370 | {
|
---|
1371 | unsigned char *p;
|
---|
1372 | int i, n = (bignum_bitcount(b) + 7) / 8;
|
---|
1373 | p = smalloc(n + 1);
|
---|
1374 | if (!p)
|
---|
1375 | fatalbox("out of memory");
|
---|
1376 | p[0] = 0;
|
---|
1377 | for (i = 1; i <= n; i++)
|
---|
1378 | p[i] = bignum_byte(b, n - i);
|
---|
1379 | i = 0;
|
---|
1380 | while (i <= n && p[i] == 0 && (p[i + 1] & 0x80) == 0)
|
---|
1381 | i++;
|
---|
1382 | memmove(p, p + i, n + 1 - i);
|
---|
1383 | *len = n + 1 - i;
|
---|
1384 | return p;
|
---|
1385 | }
|
---|
1386 | static void ssh2_pkt_addmp(Bignum b)
|
---|
1387 | {
|
---|
1388 | unsigned char *p;
|
---|
1389 | int len;
|
---|
1390 | p = ssh2_mpint_fmt(b, &len);
|
---|
1391 | ssh2_pkt_addstring_start();
|
---|
1392 | ssh2_pkt_addstring_data(p, len);
|
---|
1393 | sfree(p);
|
---|
1394 | }
|
---|
1395 |
|
---|
1396 | /*
|
---|
1397 | * Construct an SSH2 final-form packet: compress it, encrypt it,
|
---|
1398 | * put the MAC on it. Final packet, ready to be sent, is stored in
|
---|
1399 | * pktout.data. Total length is returned.
|
---|
1400 | */
|
---|
1401 | static int ssh2_pkt_construct(void)
|
---|
1402 | {
|
---|
1403 | int cipherblk, maclen, padding, i;
|
---|
1404 | static unsigned long outgoing_sequence = 0;
|
---|
1405 |
|
---|
1406 | // log_packet(PKT_OUTGOING, pktout.data[5], ssh2_pkt_type(pktout.data[5]),
|
---|
1407 | // pktout.data + 6, pktout.length - 6);
|
---|
1408 |
|
---|
1409 | /*
|
---|
1410 | * Compress packet payload.
|
---|
1411 | */
|
---|
1412 | {
|
---|
1413 | unsigned char *newpayload;
|
---|
1414 | int newlen;
|
---|
1415 | if (cscomp && cscomp->compress(pktout.data + 5, pktout.length - 5,
|
---|
1416 | &newpayload, &newlen)) {
|
---|
1417 | pktout.length = 5;
|
---|
1418 | ssh2_pkt_adddata(newpayload, newlen);
|
---|
1419 | sfree(newpayload);
|
---|
1420 | }
|
---|
1421 | }
|
---|
1422 |
|
---|
1423 | /*
|
---|
1424 | * Add padding. At least four bytes, and must also bring total
|
---|
1425 | * length (minus MAC) up to a multiple of the block size.
|
---|
1426 | */
|
---|
1427 | cipherblk = cscipher ? cscipher->blksize : 8; /* block size */
|
---|
1428 | cipherblk = cipherblk < 8 ? 8 : cipherblk; /* or 8 if blksize < 8 */
|
---|
1429 | padding = 4;
|
---|
1430 | padding +=
|
---|
1431 | (cipherblk - (pktout.length + padding) % cipherblk) % cipherblk;
|
---|
1432 | maclen = csmac ? csmac->len : 0;
|
---|
1433 | ssh2_pkt_ensure(pktout.length + padding + maclen);
|
---|
1434 | pktout.data[4] = padding;
|
---|
1435 | for (i = 0; i < padding; i++)
|
---|
1436 | pktout.data[pktout.length + i] = random_byte();
|
---|
1437 | PUT_32BIT(pktout.data, pktout.length + padding - 4);
|
---|
1438 | if (csmac)
|
---|
1439 | csmac->generate(pktout.data, pktout.length + padding,
|
---|
1440 | outgoing_sequence);
|
---|
1441 | outgoing_sequence++; /* whether or not we MACed */
|
---|
1442 |
|
---|
1443 | if (cscipher)
|
---|
1444 | cscipher->encrypt(pktout.data, pktout.length + padding);
|
---|
1445 |
|
---|
1446 | /* Ready-to-send packet starts at pktout.data. We return length. */
|
---|
1447 | return pktout.length + padding + maclen;
|
---|
1448 | }
|
---|
1449 |
|
---|
1450 | /*
|
---|
1451 | * Construct and send an SSH2 packet immediately.
|
---|
1452 | */
|
---|
1453 | static void ssh2_pkt_send(void)
|
---|
1454 | {
|
---|
1455 | int len;
|
---|
1456 | int backlog;
|
---|
1457 | len = ssh2_pkt_construct();
|
---|
1458 | backlog = sk_write(s, pktout.data, len);
|
---|
1459 | if (backlog > SSH_MAX_BACKLOG)
|
---|
1460 | ssh_throttle_all(1, backlog);
|
---|
1461 | }
|
---|
1462 |
|
---|
1463 | /*
|
---|
1464 | * Construct an SSH2 packet and add it to a deferred data block.
|
---|
1465 | * Useful for sending multiple packets in a single sk_write() call,
|
---|
1466 | * to prevent a traffic-analysing listener from being able to work
|
---|
1467 | * out the length of any particular packet (such as the password
|
---|
1468 | * packet).
|
---|
1469 | *
|
---|
1470 | * Note that because SSH2 sequence-numbers its packets, this can
|
---|
1471 | * NOT be used as an m4-style `defer' allowing packets to be
|
---|
1472 | * constructed in one order and sent in another.
|
---|
1473 | */
|
---|
1474 | static void ssh2_pkt_defer(void)
|
---|
1475 | {
|
---|
1476 | int len = ssh2_pkt_construct();
|
---|
1477 | if (deferred_len + len > deferred_size) {
|
---|
1478 | deferred_size = deferred_len + len + 128;
|
---|
1479 | deferred_send_data = srealloc(deferred_send_data, deferred_size);
|
---|
1480 | }
|
---|
1481 | memcpy(deferred_send_data + deferred_len, pktout.data, len);
|
---|
1482 | deferred_len += len;
|
---|
1483 | }
|
---|
1484 |
|
---|
1485 | /*
|
---|
1486 | * Send the whole deferred data block constructed by
|
---|
1487 | * ssh2_pkt_defer() or SSH1's defer_packet().
|
---|
1488 | */
|
---|
1489 | static void ssh_pkt_defersend(void)
|
---|
1490 | {
|
---|
1491 | int backlog;
|
---|
1492 | backlog = sk_write(s, deferred_send_data, deferred_len);
|
---|
1493 | deferred_len = deferred_size = 0;
|
---|
1494 | sfree(deferred_send_data);
|
---|
1495 | deferred_send_data = NULL;
|
---|
1496 | if (backlog > SSH_MAX_BACKLOG)
|
---|
1497 | ssh_throttle_all(1, backlog);
|
---|
1498 | }
|
---|
1499 |
|
---|
1500 | #if 0
|
---|
1501 | void bndebug(char *string, Bignum b)
|
---|
1502 | {
|
---|
1503 | unsigned char *p;
|
---|
1504 | int i, len;
|
---|
1505 | p = ssh2_mpint_fmt(b, &len);
|
---|
1506 | debug(("%s", string));
|
---|
1507 | for (i = 0; i < len; i++)
|
---|
1508 | debug((" %02x", p[i]));
|
---|
1509 | debug(("\n"));
|
---|
1510 | sfree(p);
|
---|
1511 | }
|
---|
1512 | #endif
|
---|
1513 |
|
---|
1514 | static void sha_mpint(SHA_State * s, Bignum b)
|
---|
1515 | {
|
---|
1516 | unsigned char *p;
|
---|
1517 | int len;
|
---|
1518 | p = ssh2_mpint_fmt(b, &len);
|
---|
1519 | sha_string(s, p, len);
|
---|
1520 | sfree(p);
|
---|
1521 | }
|
---|
1522 |
|
---|
1523 | /*
|
---|
1524 | * SSH2 packet decode functions.
|
---|
1525 | */
|
---|
1526 | static unsigned long ssh2_pkt_getuint32(void)
|
---|
1527 | {
|
---|
1528 | unsigned long value;
|
---|
1529 | if (pktin.length - pktin.savedpos < 4)
|
---|
1530 | return 0; /* arrgh, no way to decline (FIXME?) */
|
---|
1531 | value = GET_32BIT(pktin.data + pktin.savedpos);
|
---|
1532 | pktin.savedpos += 4;
|
---|
1533 | return value;
|
---|
1534 | }
|
---|
1535 | static int ssh2_pkt_getbool(void)
|
---|
1536 | {
|
---|
1537 | unsigned long value;
|
---|
1538 | if (pktin.length - pktin.savedpos < 1)
|
---|
1539 | return 0; /* arrgh, no way to decline (FIXME?) */
|
---|
1540 | value = pktin.data[pktin.savedpos] != 0;
|
---|
1541 | pktin.savedpos++;
|
---|
1542 | return value;
|
---|
1543 | }
|
---|
1544 | static void ssh2_pkt_getstring(char **p, int *length)
|
---|
1545 | {
|
---|
1546 | *p = NULL;
|
---|
1547 | *length = 0;
|
---|
1548 | if (pktin.length - pktin.savedpos < 4)
|
---|
1549 | return;
|
---|
1550 | *length = GET_32BIT(pktin.data + pktin.savedpos);
|
---|
1551 | pktin.savedpos += 4;
|
---|
1552 | if (pktin.length - pktin.savedpos < *length)
|
---|
1553 | return;
|
---|
1554 | *p = pktin.data + pktin.savedpos;
|
---|
1555 | pktin.savedpos += *length;
|
---|
1556 | }
|
---|
1557 | static Bignum ssh2_pkt_getmp(void)
|
---|
1558 | {
|
---|
1559 | char *p;
|
---|
1560 | int length;
|
---|
1561 | Bignum b;
|
---|
1562 |
|
---|
1563 | ssh2_pkt_getstring(&p, &length);
|
---|
1564 | if (!p)
|
---|
1565 | return NULL;
|
---|
1566 | if (p[0] & 0x80) {
|
---|
1567 | bombout(("internal error: Can't handle negative mpints"));
|
---|
1568 | return NULL;
|
---|
1569 | }
|
---|
1570 | b = bignum_from_bytes(p, length);
|
---|
1571 | return b;
|
---|
1572 | }
|
---|
1573 |
|
---|
1574 | /*
|
---|
1575 | * Helper function to add an SSH2 signature blob to a packet.
|
---|
1576 | * Expects to be shown the public key blob as well as the signature
|
---|
1577 | * blob. Normally works just like ssh2_pkt_addstring, but will
|
---|
1578 | * fiddle with the signature packet if necessary for
|
---|
1579 | * BUG_SSH2_RSA_PADDING.
|
---|
1580 | */
|
---|
1581 | static void ssh2_add_sigblob(void *pkblob_v, int pkblob_len,
|
---|
1582 | void *sigblob_v, int sigblob_len)
|
---|
1583 | {
|
---|
1584 | unsigned char *pkblob = (unsigned char *)pkblob_v;
|
---|
1585 | unsigned char *sigblob = (unsigned char *)sigblob_v;
|
---|
1586 |
|
---|
1587 | /* dmemdump(pkblob, pkblob_len); */
|
---|
1588 | /* dmemdump(sigblob, sigblob_len); */
|
---|
1589 |
|
---|
1590 | /*
|
---|
1591 | * See if this is in fact an ssh-rsa signature and a buggy
|
---|
1592 | * server; otherwise we can just do this the easy way.
|
---|
1593 | */
|
---|
1594 | if ((ssh_remote_bugs & BUG_SSH2_RSA_PADDING) &&
|
---|
1595 | (GET_32BIT(pkblob) == 7 && !memcmp(pkblob+4, "ssh-rsa", 7))) {
|
---|
1596 | int pos, len, siglen;
|
---|
1597 |
|
---|
1598 | /*
|
---|
1599 | * Find the byte length of the modulus.
|
---|
1600 | */
|
---|
1601 |
|
---|
1602 | pos = 4+7; /* skip over "ssh-rsa" */
|
---|
1603 | pos += 4 + GET_32BIT(pkblob+pos); /* skip over exponent */
|
---|
1604 | len = GET_32BIT(pkblob+pos); /* find length of modulus */
|
---|
1605 | pos += 4; /* find modulus itself */
|
---|
1606 | while (len > 0 && pkblob[pos] == 0)
|
---|
1607 | len--, pos++;
|
---|
1608 | /* debug(("modulus length is %d\n", len)); */
|
---|
1609 |
|
---|
1610 | /*
|
---|
1611 | * Now find the signature integer.
|
---|
1612 | */
|
---|
1613 | pos = 4+7; /* skip over "ssh-rsa" */
|
---|
1614 | siglen = GET_32BIT(sigblob+pos);
|
---|
1615 | /* debug(("signature length is %d\n", siglen)); */
|
---|
1616 |
|
---|
1617 | if (len != siglen) {
|
---|
1618 | unsigned char newlen[4];
|
---|
1619 | ssh2_pkt_addstring_start();
|
---|
1620 | ssh2_pkt_addstring_data(sigblob, pos);
|
---|
1621 | /* dmemdump(sigblob, pos); */
|
---|
1622 | pos += 4; /* point to start of actual sig */
|
---|
1623 | PUT_32BIT(newlen, len);
|
---|
1624 | ssh2_pkt_addstring_data(newlen, 4);
|
---|
1625 | /* dmemdump(newlen, 4); */
|
---|
1626 | newlen[0] = 0;
|
---|
1627 | while (len-- > siglen) {
|
---|
1628 | ssh2_pkt_addstring_data(newlen, 1);
|
---|
1629 | /* dmemdump(newlen, 1); */
|
---|
1630 | }
|
---|
1631 | ssh2_pkt_addstring_data(sigblob+pos, siglen);
|
---|
1632 | /* dmemdump(sigblob+pos, siglen); */
|
---|
1633 | return;
|
---|
1634 | }
|
---|
1635 |
|
---|
1636 | /* Otherwise fall through and do it the easy way. */
|
---|
1637 | }
|
---|
1638 |
|
---|
1639 | ssh2_pkt_addstring_start();
|
---|
1640 | ssh2_pkt_addstring_data(sigblob, sigblob_len);
|
---|
1641 | }
|
---|
1642 |
|
---|
1643 | /*
|
---|
1644 | * Examine the remote side's version string and compare it against
|
---|
1645 | * a list of known buggy implementations.
|
---|
1646 | */
|
---|
1647 | static void ssh_detect_bugs(char *vstring)
|
---|
1648 | {
|
---|
1649 | char *imp; /* pointer to implementation part */
|
---|
1650 | imp = vstring;
|
---|
1651 | imp += strcspn(imp, "-");
|
---|
1652 | if (*imp) imp++;
|
---|
1653 | imp += strcspn(imp, "-");
|
---|
1654 | if (*imp) imp++;
|
---|
1655 |
|
---|
1656 | ssh_remote_bugs = 0;
|
---|
1657 |
|
---|
1658 | if (!strcmp(imp, "1.2.18") || !strcmp(imp, "1.2.19") ||
|
---|
1659 | !strcmp(imp, "1.2.20") || !strcmp(imp, "1.2.21") ||
|
---|
1660 | !strcmp(imp, "1.2.22") || !strcmp(imp, "Cisco-1.25")) {
|
---|
1661 | /*
|
---|
1662 | * These versions don't support SSH1_MSG_IGNORE, so we have
|
---|
1663 | * to use a different defence against password length
|
---|
1664 | * sniffing.
|
---|
1665 | */
|
---|
1666 | ssh_remote_bugs |= BUG_CHOKES_ON_SSH1_IGNORE;
|
---|
1667 | logevent("We believe remote version has SSH1 ignore bug");
|
---|
1668 | }
|
---|
1669 |
|
---|
1670 | if (!strcmp(imp, "Cisco-1.25")) {
|
---|
1671 | /*
|
---|
1672 | * These versions need a plain password sent; they can't
|
---|
1673 | * handle having a null and a random length of data after
|
---|
1674 | * the password.
|
---|
1675 | */
|
---|
1676 | ssh_remote_bugs |= BUG_NEEDS_SSH1_PLAIN_PASSWORD;
|
---|
1677 | logevent("We believe remote version needs a plain SSH1 password");
|
---|
1678 | }
|
---|
1679 |
|
---|
1680 | if (!strcmp(imp, "Cisco-1.25")) {
|
---|
1681 | /*
|
---|
1682 | * These versions apparently have no clue whatever about
|
---|
1683 | * RSA authentication and will panic and die if they see
|
---|
1684 | * an AUTH_RSA message.
|
---|
1685 | */
|
---|
1686 | ssh_remote_bugs |= BUG_CHOKES_ON_RSA;
|
---|
1687 | logevent("We believe remote version can't handle RSA authentication");
|
---|
1688 | }
|
---|
1689 |
|
---|
1690 | if (!strncmp(imp, "2.1.0", 5) || !strncmp(imp, "2.0.", 4) ||
|
---|
1691 | !strncmp(imp, "2.2.0", 5) || !strncmp(imp, "2.3.0", 5) ||
|
---|
1692 | !strncmp(imp, "2.1 ", 4)) {
|
---|
1693 | /*
|
---|
1694 | * These versions have the HMAC bug.
|
---|
1695 | */
|
---|
1696 | ssh_remote_bugs |= BUG_SSH2_HMAC;
|
---|
1697 | logevent("We believe remote version has SSH2 HMAC bug");
|
---|
1698 | }
|
---|
1699 |
|
---|
1700 | if (!strncmp(imp, "2.0.", 4)) {
|
---|
1701 | /*
|
---|
1702 | * These versions have the key-derivation bug (failing to
|
---|
1703 | * include the literal shared secret in the hashes that
|
---|
1704 | * generate the keys).
|
---|
1705 | */
|
---|
1706 | ssh_remote_bugs |= BUG_SSH2_DERIVEKEY;
|
---|
1707 | logevent("We believe remote version has SSH2 key-derivation bug");
|
---|
1708 | }
|
---|
1709 |
|
---|
1710 | if ((!strncmp(imp, "OpenSSH_2.", 10) && imp[10]>='5' && imp[10]<='9') ||
|
---|
1711 | (!strncmp(imp, "OpenSSH_3.", 10) && imp[10]>='0' && imp[10]<='2')) {
|
---|
1712 | /*
|
---|
1713 | * These versions have the SSH2 RSA padding bug.
|
---|
1714 | */
|
---|
1715 | ssh_remote_bugs |= BUG_SSH2_RSA_PADDING;
|
---|
1716 | logevent("We believe remote version has SSH2 RSA padding bug");
|
---|
1717 | }
|
---|
1718 | }
|
---|
1719 |
|
---|
1720 | static int do_ssh_init(unsigned char c)
|
---|
1721 | {
|
---|
1722 | static int vslen;
|
---|
1723 | static char version[10];
|
---|
1724 | static char *vstring;
|
---|
1725 | static int vstrsize;
|
---|
1726 | static char *vlog;
|
---|
1727 | static int i;
|
---|
1728 | static int proto1, proto2;
|
---|
1729 |
|
---|
1730 | crBegin;
|
---|
1731 |
|
---|
1732 | /* Search for the string "SSH-" in the input. */
|
---|
1733 | i = 0;
|
---|
1734 | while (1) {
|
---|
1735 | static const int transS[] = { 1, 2, 2, 1 };
|
---|
1736 | static const int transH[] = { 0, 0, 3, 0 };
|
---|
1737 | static const int transminus[] = { 0, 0, 0, -1 };
|
---|
1738 | if (c == 'S')
|
---|
1739 | i = transS[i];
|
---|
1740 | else if (c == 'H')
|
---|
1741 | i = transH[i];
|
---|
1742 | else if (c == '-')
|
---|
1743 | i = transminus[i];
|
---|
1744 | else
|
---|
1745 | i = 0;
|
---|
1746 | if (i < 0)
|
---|
1747 | break;
|
---|
1748 | crReturn(1); /* get another character */
|
---|
1749 | }
|
---|
1750 |
|
---|
1751 | vstrsize = 16;
|
---|
1752 | vstring = smalloc(vstrsize);
|
---|
1753 | strcpy(vstring, "SSH-");
|
---|
1754 | vslen = 4;
|
---|
1755 | i = 0;
|
---|
1756 | while (1) {
|
---|
1757 | crReturn(1); /* get another char */
|
---|
1758 | if (vslen >= vstrsize - 1) {
|
---|
1759 | vstrsize += 16;
|
---|
1760 | vstring = srealloc(vstring, vstrsize);
|
---|
1761 | }
|
---|
1762 | vstring[vslen++] = c;
|
---|
1763 | if (i >= 0) {
|
---|
1764 | if (c == '-') {
|
---|
1765 | version[i] = '\0';
|
---|
1766 | i = -1;
|
---|
1767 | } else if (i < sizeof(version) - 1)
|
---|
1768 | version[i++] = c;
|
---|
1769 | } else if (c == '\n')
|
---|
1770 | break;
|
---|
1771 | }
|
---|
1772 |
|
---|
1773 | ssh_agentfwd_enabled = FALSE;
|
---|
1774 | rdpkt2_state.incoming_sequence = 0;
|
---|
1775 |
|
---|
1776 | vstring[vslen] = 0;
|
---|
1777 | vlog = smalloc(20 + vslen);
|
---|
1778 | vstring[strcspn (vstring, "\r\n")] = '\0'; /* remove end-of-line chars */
|
---|
1779 | sprintf(vlog, "Server version: %s", vstring);
|
---|
1780 | logevent(vlog);
|
---|
1781 | ssh_detect_bugs(vstring);
|
---|
1782 | sfree(vlog);
|
---|
1783 |
|
---|
1784 | /*
|
---|
1785 | * Decide which SSH protocol version to support.
|
---|
1786 | */
|
---|
1787 |
|
---|
1788 | /* Anything strictly below "2.0" means protocol 1 is supported. */
|
---|
1789 | proto1 = ssh_versioncmp(version, "2.0") < 0;
|
---|
1790 | /* Anything greater or equal to "1.99" means protocol 2 is supported. */
|
---|
1791 | proto2 = ssh_versioncmp(version, "1.99") >= 0;
|
---|
1792 |
|
---|
1793 | if (cfg.sshprot == 0 && !proto1) {
|
---|
1794 | bombout(("SSH protocol version 1 required by user but not provided by server"));
|
---|
1795 | crReturn(0);
|
---|
1796 | }
|
---|
1797 | if (cfg.sshprot == 3 && !proto2) {
|
---|
1798 | bombout(("SSH protocol version 2 required by user but not provided by server"));
|
---|
1799 | crReturn(0);
|
---|
1800 | }
|
---|
1801 |
|
---|
1802 | if (proto2 && (cfg.sshprot >= 2 || !proto1)) {
|
---|
1803 | /*
|
---|
1804 | * Use v2 protocol.
|
---|
1805 | */
|
---|
1806 | char verstring[80], vlog[100];
|
---|
1807 | sprintf(verstring, "SSH-2.0-%s", sshver);
|
---|
1808 | SHA_Init(&exhashbase);
|
---|
1809 | /*
|
---|
1810 | * Hash our version string and their version string.
|
---|
1811 | */
|
---|
1812 | sha_string(&exhashbase, verstring, strlen(verstring));
|
---|
1813 | sha_string(&exhashbase, vstring, strcspn(vstring, "\r\n"));
|
---|
1814 | sprintf(vlog, "We claim version: %s", verstring);
|
---|
1815 | logevent(vlog);
|
---|
1816 | strcat(verstring, "\n");
|
---|
1817 | logevent("Using SSH protocol version 2");
|
---|
1818 | sk_write(s, verstring, strlen(verstring));
|
---|
1819 | ssh_protocol = ssh2_protocol;
|
---|
1820 | ssh_version = 2;
|
---|
1821 | s_rdpkt = ssh2_rdpkt;
|
---|
1822 | } else {
|
---|
1823 | /*
|
---|
1824 | * Use v1 protocol.
|
---|
1825 | */
|
---|
1826 | char verstring[80], vlog[100];
|
---|
1827 | sprintf(verstring, "SSH-%s-%s",
|
---|
1828 | (ssh_versioncmp(version, "1.5") <= 0 ? version : "1.5"),
|
---|
1829 | sshver);
|
---|
1830 | sprintf(vlog, "We claim version: %s", verstring);
|
---|
1831 | logevent(vlog);
|
---|
1832 | strcat(verstring, "\n");
|
---|
1833 |
|
---|
1834 | logevent("Using SSH protocol version 1");
|
---|
1835 | sk_write(s, verstring, strlen(verstring));
|
---|
1836 | ssh_protocol = ssh1_protocol;
|
---|
1837 | ssh_version = 1;
|
---|
1838 | s_rdpkt = ssh1_rdpkt;
|
---|
1839 | }
|
---|
1840 | ssh_state = SSH_STATE_BEFORE_SIZE;
|
---|
1841 |
|
---|
1842 | sfree(vstring);
|
---|
1843 |
|
---|
1844 | crFinish(0);
|
---|
1845 | }
|
---|
1846 |
|
---|
1847 | static void ssh_gotdata(unsigned char *data, int datalen)
|
---|
1848 | {
|
---|
1849 | crBegin;
|
---|
1850 |
|
---|
1851 | /*
|
---|
1852 | * To begin with, feed the characters one by one to the
|
---|
1853 | * protocol initialisation / selection function do_ssh_init().
|
---|
1854 | * When that returns 0, we're done with the initial greeting
|
---|
1855 | * exchange and can move on to packet discipline.
|
---|
1856 | */
|
---|
1857 | while (1) {
|
---|
1858 | int ret;
|
---|
1859 | if (datalen == 0)
|
---|
1860 | crReturnV; /* more data please */
|
---|
1861 | ret = do_ssh_init(*data);
|
---|
1862 | data++;
|
---|
1863 | datalen--;
|
---|
1864 | if (ret == 0)
|
---|
1865 | break;
|
---|
1866 | }
|
---|
1867 |
|
---|
1868 | /*
|
---|
1869 | * We emerge from that loop when the initial negotiation is
|
---|
1870 | * over and we have selected an s_rdpkt function. Now pass
|
---|
1871 | * everything to s_rdpkt, and then pass the resulting packets
|
---|
1872 | * to the proper protocol handler.
|
---|
1873 | */
|
---|
1874 | if (datalen == 0)
|
---|
1875 | crReturnV;
|
---|
1876 | while (1) {
|
---|
1877 | while (datalen > 0) {
|
---|
1878 | if (s_rdpkt(&data, &datalen) == 0) {
|
---|
1879 | if (ssh_state == SSH_STATE_CLOSED) {
|
---|
1880 | return;
|
---|
1881 | }
|
---|
1882 | ssh_protocol(NULL, 0, 1);
|
---|
1883 | if (ssh_state == SSH_STATE_CLOSED) {
|
---|
1884 | return;
|
---|
1885 | }
|
---|
1886 | }
|
---|
1887 | }
|
---|
1888 | crReturnV;
|
---|
1889 | }
|
---|
1890 | crFinishV;
|
---|
1891 | }
|
---|
1892 |
|
---|
1893 | static int ssh_closing(Plug plug, char *error_msg, int error_code,
|
---|
1894 | int calling_back)
|
---|
1895 | {
|
---|
1896 | ssh_state = SSH_STATE_CLOSED;
|
---|
1897 | if (s) {
|
---|
1898 | sk_close(s);
|
---|
1899 | s = NULL;
|
---|
1900 | }
|
---|
1901 | if (error_msg) {
|
---|
1902 | /* A socket error has occurred. */
|
---|
1903 | connection_fatal(error_msg);
|
---|
1904 | } else {
|
---|
1905 | /* Otherwise, the remote side closed the connection normally. */
|
---|
1906 | }
|
---|
1907 | return 0;
|
---|
1908 | }
|
---|
1909 |
|
---|
1910 | static int ssh_receive(Plug plug, int urgent, char *data, int len)
|
---|
1911 | {
|
---|
1912 | ssh_gotdata(data, len);
|
---|
1913 | if (ssh_state == SSH_STATE_CLOSED) {
|
---|
1914 | if (s) {
|
---|
1915 | sk_close(s);
|
---|
1916 | s = NULL;
|
---|
1917 | }
|
---|
1918 | return 0;
|
---|
1919 | }
|
---|
1920 | return 1;
|
---|
1921 | }
|
---|
1922 |
|
---|
1923 | static void ssh_sent(Plug plug, int bufsize)
|
---|
1924 | {
|
---|
1925 | /*
|
---|
1926 | * If the send backlog on the SSH socket itself clears, we
|
---|
1927 | * should unthrottle the whole world if it was throttled.
|
---|
1928 | */
|
---|
1929 | if (bufsize < SSH_MAX_BACKLOG)
|
---|
1930 | ssh_throttle_all(0, bufsize);
|
---|
1931 | }
|
---|
1932 |
|
---|
1933 | /*
|
---|
1934 | * Connect to specified host and port.
|
---|
1935 | * Returns an error message, or NULL on success.
|
---|
1936 | * Also places the canonical host name into `realhost'. It must be
|
---|
1937 | * freed by the caller.
|
---|
1938 | */
|
---|
1939 | static char *connect_to_host(char *host, int port, char **realhost, int nodelay)
|
---|
1940 | {
|
---|
1941 | static struct plug_function_table fn_table = {
|
---|
1942 | ssh_closing,
|
---|
1943 | ssh_receive,
|
---|
1944 | ssh_sent,
|
---|
1945 | NULL
|
---|
1946 | }, *fn_table_ptr = &fn_table;
|
---|
1947 |
|
---|
1948 | SockAddr addr={0};
|
---|
1949 | char *err;
|
---|
1950 | #ifdef FWHACK
|
---|
1951 | char *FWhost;
|
---|
1952 | int FWport;
|
---|
1953 | #endif
|
---|
1954 |
|
---|
1955 | savedhost = smalloc(1 + strlen(host));
|
---|
1956 | if (!savedhost)
|
---|
1957 | fatalbox("Out of memory");
|
---|
1958 | strcpy(savedhost, host);
|
---|
1959 |
|
---|
1960 | if (port < 0)
|
---|
1961 | port = 22; /* default ssh port */
|
---|
1962 | savedport = port;
|
---|
1963 |
|
---|
1964 | #ifdef FWHACK
|
---|
1965 | FWhost = host;
|
---|
1966 | FWport = port;
|
---|
1967 | host = FWSTR;
|
---|
1968 | port = 23;
|
---|
1969 | #endif
|
---|
1970 |
|
---|
1971 | s = new_connection(addr, *realhost, port, 0, 1, nodelay, &fn_table_ptr);
|
---|
1972 | if ((err = sk_socket_error(s))) {
|
---|
1973 | s = NULL;
|
---|
1974 | return err;
|
---|
1975 | }
|
---|
1976 |
|
---|
1977 | #ifdef FWHACK
|
---|
1978 | sk_write(s, "connect ", 8);
|
---|
1979 | sk_write(s, FWhost, strlen(FWhost));
|
---|
1980 | {
|
---|
1981 | char buf[20];
|
---|
1982 | sprintf(buf, " %d\n", FWport);
|
---|
1983 | sk_write(s, buf, strlen(buf));
|
---|
1984 | }
|
---|
1985 | #endif
|
---|
1986 |
|
---|
1987 | return NULL;
|
---|
1988 | }
|
---|
1989 |
|
---|
1990 | /*
|
---|
1991 | * Throttle or unthrottle the SSH connection.
|
---|
1992 | */
|
---|
1993 | static void ssh1_throttle(int adjust)
|
---|
1994 | {
|
---|
1995 | int old_count = ssh1_throttle_count;
|
---|
1996 | ssh1_throttle_count += adjust;
|
---|
1997 | assert(ssh1_throttle_count >= 0);
|
---|
1998 | if (ssh1_throttle_count && !old_count) {
|
---|
1999 | sk_set_frozen(s, 1);
|
---|
2000 | } else if (!ssh1_throttle_count && old_count) {
|
---|
2001 | sk_set_frozen(s, 0);
|
---|
2002 | }
|
---|
2003 | }
|
---|
2004 |
|
---|
2005 | /*
|
---|
2006 | * Throttle or unthrottle _all_ local data streams (for when sends
|
---|
2007 | * on the SSH connection itself back up).
|
---|
2008 | */
|
---|
2009 | static void ssh_throttle_all(int enable, int bufsize)
|
---|
2010 | {
|
---|
2011 | int i;
|
---|
2012 | struct ssh_channel *c;
|
---|
2013 |
|
---|
2014 | if (enable == ssh_throttled_all)
|
---|
2015 | return;
|
---|
2016 | ssh_throttled_all = enable;
|
---|
2017 | ssh_overall_bufsize = bufsize;
|
---|
2018 | if (!ssh_channels)
|
---|
2019 | return;
|
---|
2020 | for (i = 0; NULL != (c = index234(ssh_channels, i)); i++) {
|
---|
2021 | switch (c->type) {
|
---|
2022 | case CHAN_MAINSESSION:
|
---|
2023 | /*
|
---|
2024 | * This is treated separately, outside the switch.
|
---|
2025 | */
|
---|
2026 | break;
|
---|
2027 | case CHAN_X11:
|
---|
2028 | // x11_override_throttle(c->u.x11.s, enable);
|
---|
2029 | break;
|
---|
2030 | case CHAN_AGENT:
|
---|
2031 | /* Agent channels require no buffer management. */
|
---|
2032 | break;
|
---|
2033 | case CHAN_SOCKDATA:
|
---|
2034 | pfd_override_throttle(c->u.x11.s, enable);
|
---|
2035 | break;
|
---|
2036 | }
|
---|
2037 | }
|
---|
2038 | }
|
---|
2039 |
|
---|
2040 | /*
|
---|
2041 | * Handle the key exchange and user authentication phases.
|
---|
2042 | */
|
---|
2043 | static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
|
---|
2044 | {
|
---|
2045 | int i, j;
|
---|
2046 | static int len;
|
---|
2047 | static unsigned char *rsabuf, *keystr1, *keystr2;
|
---|
2048 | unsigned char cookie[8];
|
---|
2049 | struct RSAKey servkey, hostkey;
|
---|
2050 | struct MD5Context md5c;
|
---|
2051 | static unsigned long supported_ciphers_mask, supported_auths_mask;
|
---|
2052 | static int tried_publickey, tried_agent;
|
---|
2053 | static int tis_auth_refused, ccard_auth_refused;
|
---|
2054 | static unsigned char session_id[16];
|
---|
2055 | static int cipher_type;
|
---|
2056 | static char username[100];
|
---|
2057 | static void *publickey_blob;
|
---|
2058 | int publickey_bloblen;
|
---|
2059 |
|
---|
2060 | crBegin;
|
---|
2061 |
|
---|
2062 | if (!ispkt)
|
---|
2063 | crWaitUntil(ispkt);
|
---|
2064 |
|
---|
2065 | if (pktin.type != SSH1_SMSG_PUBLIC_KEY) {
|
---|
2066 | bombout(("Public key packet not received"));
|
---|
2067 | crReturn(0);
|
---|
2068 | }
|
---|
2069 |
|
---|
2070 | logevent("Received public keys");
|
---|
2071 |
|
---|
2072 | memcpy(cookie, pktin.body, 8);
|
---|
2073 |
|
---|
2074 | i = makekey(pktin.body + 8, &servkey, &keystr1, 0);
|
---|
2075 | j = makekey(pktin.body + 8 + i, &hostkey, &keystr2, 0);
|
---|
2076 |
|
---|
2077 | /*
|
---|
2078 | * Log the host key fingerprint.
|
---|
2079 | */
|
---|
2080 | {
|
---|
2081 | char logmsg[80];
|
---|
2082 | logevent("Host key fingerprint is:");
|
---|
2083 | strcpy(logmsg, " ");
|
---|
2084 | hostkey.comment = NULL;
|
---|
2085 | rsa_fingerprint(logmsg + strlen(logmsg),
|
---|
2086 | sizeof(logmsg) - strlen(logmsg), &hostkey);
|
---|
2087 | logevent(logmsg);
|
---|
2088 | }
|
---|
2089 |
|
---|
2090 | ssh1_remote_protoflags = GET_32BIT(pktin.body + 8 + i + j);
|
---|
2091 | supported_ciphers_mask = GET_32BIT(pktin.body + 12 + i + j);
|
---|
2092 | supported_auths_mask = GET_32BIT(pktin.body + 16 + i + j);
|
---|
2093 |
|
---|
2094 | ssh1_local_protoflags =
|
---|
2095 | ssh1_remote_protoflags & SSH1_PROTOFLAGS_SUPPORTED;
|
---|
2096 | ssh1_local_protoflags |= SSH1_PROTOFLAG_SCREEN_NUMBER;
|
---|
2097 |
|
---|
2098 | MD5Init(&md5c);
|
---|
2099 | MD5Update(&md5c, keystr2, hostkey.bytes);
|
---|
2100 | MD5Update(&md5c, keystr1, servkey.bytes);
|
---|
2101 | MD5Update(&md5c, pktin.body, 8);
|
---|
2102 | MD5Final(session_id, &md5c);
|
---|
2103 |
|
---|
2104 | for (i = 0; i < 32; i++)
|
---|
2105 | session_key[i] = random_byte();
|
---|
2106 |
|
---|
2107 | len = (hostkey.bytes > servkey.bytes ? hostkey.bytes : servkey.bytes);
|
---|
2108 |
|
---|
2109 | rsabuf = smalloc(len);
|
---|
2110 | if (!rsabuf)
|
---|
2111 | fatalbox("Out of memory");
|
---|
2112 |
|
---|
2113 | /*
|
---|
2114 | * Verify the host key.
|
---|
2115 | */
|
---|
2116 | {
|
---|
2117 | /*
|
---|
2118 | * First format the key into a string.
|
---|
2119 | */
|
---|
2120 | int len = rsastr_len(&hostkey);
|
---|
2121 | char fingerprint[100];
|
---|
2122 | char *keystr = smalloc(len);
|
---|
2123 | if (!keystr)
|
---|
2124 | fatalbox("Out of memory");
|
---|
2125 | rsastr_fmt(keystr, &hostkey);
|
---|
2126 | rsa_fingerprint(fingerprint, sizeof(fingerprint), &hostkey);
|
---|
2127 | verify_ssh_host_key(savedhost, savedport, "rsa", keystr,
|
---|
2128 | fingerprint);
|
---|
2129 | sfree(keystr);
|
---|
2130 | }
|
---|
2131 |
|
---|
2132 | for (i = 0; i < 32; i++) {
|
---|
2133 | rsabuf[i] = session_key[i];
|
---|
2134 | if (i < 16)
|
---|
2135 | rsabuf[i] ^= session_id[i];
|
---|
2136 | }
|
---|
2137 |
|
---|
2138 | if (hostkey.bytes > servkey.bytes) {
|
---|
2139 | rsaencrypt(rsabuf, 32, &servkey);
|
---|
2140 | rsaencrypt(rsabuf, servkey.bytes, &hostkey);
|
---|
2141 | } else {
|
---|
2142 | rsaencrypt(rsabuf, 32, &hostkey);
|
---|
2143 | rsaencrypt(rsabuf, hostkey.bytes, &servkey);
|
---|
2144 | }
|
---|
2145 |
|
---|
2146 | logevent("Encrypted session key");
|
---|
2147 |
|
---|
2148 | {
|
---|
2149 | int cipher_chosen = 0, warn = 0;
|
---|
2150 | char *cipher_string = NULL;
|
---|
2151 | for (i = 0; !cipher_chosen && i < CIPHER_MAX; i++) {
|
---|
2152 | int next_cipher = cfg.ssh_cipherlist[i];
|
---|
2153 | if (next_cipher == CIPHER_WARN) {
|
---|
2154 | /* If/when we choose a cipher, warn about it */
|
---|
2155 | warn = 1;
|
---|
2156 | } else if (next_cipher == CIPHER_AES) {
|
---|
2157 | /* XXX Probably don't need to mention this. */
|
---|
2158 | logevent("AES not supported in SSH1, skipping");
|
---|
2159 | } else {
|
---|
2160 | switch (next_cipher) {
|
---|
2161 | case CIPHER_3DES: cipher_type = SSH_CIPHER_3DES;
|
---|
2162 | cipher_string = "3DES"; break;
|
---|
2163 | case CIPHER_BLOWFISH: cipher_type = SSH_CIPHER_BLOWFISH;
|
---|
2164 | cipher_string = "Blowfish"; break;
|
---|
2165 | case CIPHER_DES: cipher_type = SSH_CIPHER_DES;
|
---|
2166 | cipher_string = "single-DES"; break;
|
---|
2167 | }
|
---|
2168 | if (supported_ciphers_mask & (1 << cipher_type))
|
---|
2169 | cipher_chosen = 1;
|
---|
2170 | }
|
---|
2171 | }
|
---|
2172 | if (!cipher_chosen) {
|
---|
2173 | if ((supported_ciphers_mask & (1 << SSH_CIPHER_3DES)) == 0)
|
---|
2174 | bombout(("Server violates SSH 1 protocol by not "
|
---|
2175 | "supporting 3DES encryption"));
|
---|
2176 | else
|
---|
2177 | /* shouldn't happen */
|
---|
2178 | bombout(("No supported ciphers found"));
|
---|
2179 | crReturn(0);
|
---|
2180 | }
|
---|
2181 |
|
---|
2182 | /* Warn about chosen cipher if necessary. */
|
---|
2183 | if (warn)
|
---|
2184 | askcipher(cipher_string, 0);
|
---|
2185 | }
|
---|
2186 |
|
---|
2187 | switch (cipher_type) {
|
---|
2188 | case SSH_CIPHER_3DES:
|
---|
2189 | logevent("Using 3DES encryption");
|
---|
2190 | break;
|
---|
2191 | case SSH_CIPHER_DES:
|
---|
2192 | logevent("Using single-DES encryption");
|
---|
2193 | break;
|
---|
2194 | case SSH_CIPHER_BLOWFISH:
|
---|
2195 | logevent("Using Blowfish encryption");
|
---|
2196 | break;
|
---|
2197 | }
|
---|
2198 |
|
---|
2199 | send_packet(SSH1_CMSG_SESSION_KEY,
|
---|
2200 | PKT_CHAR, cipher_type,
|
---|
2201 | PKT_DATA, cookie, 8,
|
---|
2202 | PKT_CHAR, (len * 8) >> 8, PKT_CHAR, (len * 8) & 0xFF,
|
---|
2203 | PKT_DATA, rsabuf, len,
|
---|
2204 | PKT_INT, ssh1_local_protoflags, PKT_END);
|
---|
2205 |
|
---|
2206 | logevent("Trying to enable encryption...");
|
---|
2207 |
|
---|
2208 | sfree(rsabuf);
|
---|
2209 |
|
---|
2210 | cipher = cipher_type == SSH_CIPHER_BLOWFISH ? &ssh_blowfish_ssh1 :
|
---|
2211 | cipher_type == SSH_CIPHER_DES ? &ssh_des : &ssh_3des;
|
---|
2212 | cipher->sesskey(session_key);
|
---|
2213 |
|
---|
2214 | crWaitUntil(ispkt);
|
---|
2215 |
|
---|
2216 | if (pktin.type != SSH1_SMSG_SUCCESS) {
|
---|
2217 | bombout(("Encryption not successfully enabled"));
|
---|
2218 | crReturn(0);
|
---|
2219 | }
|
---|
2220 |
|
---|
2221 | logevent("Successfully started encryption");
|
---|
2222 |
|
---|
2223 | fflush(stdout);
|
---|
2224 | {
|
---|
2225 | if (!*cfg.username) {
|
---|
2226 | /*
|
---|
2227 | * no username provided
|
---|
2228 | * Terminate.
|
---|
2229 | */
|
---|
2230 | logevent("No username provided. Abandoning session.");
|
---|
2231 | ssh_state = SSH_STATE_CLOSED;
|
---|
2232 | crReturn(1);
|
---|
2233 | } else {
|
---|
2234 | strncpy(username, cfg.username, 99);
|
---|
2235 | username[99] = '\0';
|
---|
2236 | }
|
---|
2237 |
|
---|
2238 | send_packet(SSH1_CMSG_USER, PKT_STR, username, PKT_END);
|
---|
2239 | {
|
---|
2240 | char userlog[22 + sizeof(username)];
|
---|
2241 | sprintf(userlog, "Sent username \"%s\"", username);
|
---|
2242 | logevent(userlog);
|
---|
2243 | if (flags & FLAG_INTERACTIVE &&
|
---|
2244 | (!((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)))) {
|
---|
2245 | strcat(userlog, "\r\n");
|
---|
2246 | c_write_str(userlog);
|
---|
2247 | }
|
---|
2248 | }
|
---|
2249 | }
|
---|
2250 |
|
---|
2251 | crWaitUntil(ispkt);
|
---|
2252 |
|
---|
2253 | if ((ssh_remote_bugs & BUG_CHOKES_ON_RSA)) {
|
---|
2254 | /* We must not attempt PK auth. Pretend we've already tried it. */
|
---|
2255 | tried_publickey = tried_agent = 1;
|
---|
2256 | } else {
|
---|
2257 | tried_publickey = tried_agent = 0;
|
---|
2258 | }
|
---|
2259 | tis_auth_refused = ccard_auth_refused = 0;
|
---|
2260 | /* Load the public half of cfg.keyfile so we notice if it's in Pageant */
|
---|
2261 | if (*cfg.keyfile) {
|
---|
2262 | if (!rsakey_pubblob(cfg.keyfile, &publickey_blob, &publickey_bloblen))
|
---|
2263 | publickey_blob = NULL;
|
---|
2264 | } else
|
---|
2265 | publickey_blob = NULL;
|
---|
2266 |
|
---|
2267 | while (pktin.type == SSH1_SMSG_FAILURE) {
|
---|
2268 | static char password[100];
|
---|
2269 | static char prompt[200];
|
---|
2270 | static int pos;
|
---|
2271 | static char c;
|
---|
2272 | static int pwpkt_type;
|
---|
2273 | pwpkt_type = SSH1_CMSG_AUTH_PASSWORD;
|
---|
2274 |
|
---|
2275 | if (agent_exists() && !tried_agent) {
|
---|
2276 | /*
|
---|
2277 | * Attempt RSA authentication using Pageant.
|
---|
2278 | */
|
---|
2279 | static unsigned char request[5], *response, *p;
|
---|
2280 | static int responselen;
|
---|
2281 | static int i, nkeys;
|
---|
2282 | static int authed = FALSE;
|
---|
2283 | void *r;
|
---|
2284 |
|
---|
2285 | tried_agent = 1;
|
---|
2286 | logevent("Pageant is running. Requesting keys.");
|
---|
2287 |
|
---|
2288 | /* Request the keys held by the agent. */
|
---|
2289 | PUT_32BIT(request, 1);
|
---|
2290 | request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES;
|
---|
2291 | agent_query(request, 5, &r, &responselen);
|
---|
2292 | response = (unsigned char *) r;
|
---|
2293 | if (response && responselen >= 5 &&
|
---|
2294 | response[4] == SSH1_AGENT_RSA_IDENTITIES_ANSWER) {
|
---|
2295 | p = response + 5;
|
---|
2296 | nkeys = GET_32BIT(p);
|
---|
2297 | p += 4;
|
---|
2298 | {
|
---|
2299 | char buf[64];
|
---|
2300 | sprintf(buf, "Pageant has %d SSH1 keys", nkeys);
|
---|
2301 | logevent(buf);
|
---|
2302 | }
|
---|
2303 | for (i = 0; i < nkeys; i++) {
|
---|
2304 | static struct RSAKey key;
|
---|
2305 | static Bignum challenge;
|
---|
2306 | static char *commentp;
|
---|
2307 | static int commentlen;
|
---|
2308 |
|
---|
2309 | {
|
---|
2310 | char buf[64];
|
---|
2311 | sprintf(buf, "Trying Pageant key #%d", i);
|
---|
2312 | logevent(buf);
|
---|
2313 | }
|
---|
2314 | if (publickey_blob &&
|
---|
2315 | !memcmp(p, publickey_blob, publickey_bloblen)) {
|
---|
2316 | logevent("This key matches configured key file");
|
---|
2317 | tried_publickey = 1;
|
---|
2318 | }
|
---|
2319 | p += 4;
|
---|
2320 | p += ssh1_read_bignum(p, &key.exponent);
|
---|
2321 | p += ssh1_read_bignum(p, &key.modulus);
|
---|
2322 | commentlen = GET_32BIT(p);
|
---|
2323 | p += 4;
|
---|
2324 | commentp = p;
|
---|
2325 | p += commentlen;
|
---|
2326 | send_packet(SSH1_CMSG_AUTH_RSA,
|
---|
2327 | PKT_BIGNUM, key.modulus, PKT_END);
|
---|
2328 | crWaitUntil(ispkt);
|
---|
2329 | if (pktin.type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
|
---|
2330 | logevent("Key refused");
|
---|
2331 | continue;
|
---|
2332 | }
|
---|
2333 | logevent("Received RSA challenge");
|
---|
2334 | ssh1_read_bignum(pktin.body, &challenge);
|
---|
2335 | {
|
---|
2336 | char *agentreq, *q, *ret;
|
---|
2337 | void *vret;
|
---|
2338 | int len, retlen;
|
---|
2339 | len = 1 + 4; /* message type, bit count */
|
---|
2340 | len += ssh1_bignum_length(key.exponent);
|
---|
2341 | len += ssh1_bignum_length(key.modulus);
|
---|
2342 | len += ssh1_bignum_length(challenge);
|
---|
2343 | len += 16; /* session id */
|
---|
2344 | len += 4; /* response format */
|
---|
2345 | agentreq = smalloc(4 + len);
|
---|
2346 | PUT_32BIT(agentreq, len);
|
---|
2347 | q = agentreq + 4;
|
---|
2348 | *q++ = SSH1_AGENTC_RSA_CHALLENGE;
|
---|
2349 | PUT_32BIT(q, bignum_bitcount(key.modulus));
|
---|
2350 | q += 4;
|
---|
2351 | q += ssh1_write_bignum(q, key.exponent);
|
---|
2352 | q += ssh1_write_bignum(q, key.modulus);
|
---|
2353 | q += ssh1_write_bignum(q, challenge);
|
---|
2354 | memcpy(q, session_id, 16);
|
---|
2355 | q += 16;
|
---|
2356 | PUT_32BIT(q, 1); /* response format */
|
---|
2357 | agent_query(agentreq, len + 4, &vret, &retlen);
|
---|
2358 | ret = vret;
|
---|
2359 | sfree(agentreq);
|
---|
2360 | if (ret) {
|
---|
2361 | if (ret[4] == SSH1_AGENT_RSA_RESPONSE) {
|
---|
2362 | logevent("Sending Pageant's response");
|
---|
2363 | send_packet(SSH1_CMSG_AUTH_RSA_RESPONSE,
|
---|
2364 | PKT_DATA, ret + 5, 16,
|
---|
2365 | PKT_END);
|
---|
2366 | sfree(ret);
|
---|
2367 | crWaitUntil(ispkt);
|
---|
2368 | if (pktin.type == SSH1_SMSG_SUCCESS) {
|
---|
2369 | logevent
|
---|
2370 | ("Pageant's response accepted");
|
---|
2371 | if (flags & FLAG_VERBOSE) {
|
---|
2372 | c_write_str
|
---|
2373 | ("Authenticated using RSA key \"");
|
---|
2374 | c_write(commentp, commentlen);
|
---|
2375 | c_write_str("\" from agent\r\n");
|
---|
2376 | }
|
---|
2377 | authed = TRUE;
|
---|
2378 | } else
|
---|
2379 | logevent
|
---|
2380 | ("Pageant's response not accepted");
|
---|
2381 | } else {
|
---|
2382 | logevent
|
---|
2383 | ("Pageant failed to answer challenge");
|
---|
2384 | sfree(ret);
|
---|
2385 | }
|
---|
2386 | } else {
|
---|
2387 | logevent("No reply received from Pageant");
|
---|
2388 | }
|
---|
2389 | }
|
---|
2390 | freebn(key.exponent);
|
---|
2391 | freebn(key.modulus);
|
---|
2392 | freebn(challenge);
|
---|
2393 | if (authed)
|
---|
2394 | break;
|
---|
2395 | }
|
---|
2396 | }
|
---|
2397 | if (authed)
|
---|
2398 | break;
|
---|
2399 | }
|
---|
2400 | if (*cfg.keyfile && !tried_publickey)
|
---|
2401 | pwpkt_type = SSH1_CMSG_AUTH_RSA;
|
---|
2402 |
|
---|
2403 | if (cfg.try_tis_auth &&
|
---|
2404 | (supported_auths_mask & (1 << SSH1_AUTH_TIS)) &&
|
---|
2405 | !tis_auth_refused) {
|
---|
2406 | pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE;
|
---|
2407 | logevent("Requested TIS authentication");
|
---|
2408 | send_packet(SSH1_CMSG_AUTH_TIS, PKT_END);
|
---|
2409 | crWaitUntil(ispkt);
|
---|
2410 | if (pktin.type != SSH1_SMSG_AUTH_TIS_CHALLENGE) {
|
---|
2411 | logevent("TIS authentication declined");
|
---|
2412 | if (flags & FLAG_INTERACTIVE)
|
---|
2413 | c_write_str("TIS authentication refused.\r\n");
|
---|
2414 | tis_auth_refused = 1;
|
---|
2415 | continue;
|
---|
2416 | } else {
|
---|
2417 | int challengelen = ((pktin.body[0] << 24) |
|
---|
2418 | (pktin.body[1] << 16) |
|
---|
2419 | (pktin.body[2] << 8) |
|
---|
2420 | (pktin.body[3]));
|
---|
2421 | logevent("Received TIS challenge");
|
---|
2422 | if (challengelen > sizeof(prompt) - 1)
|
---|
2423 | challengelen = sizeof(prompt) - 1; /* prevent overrun */
|
---|
2424 | memcpy(prompt, pktin.body + 4, challengelen);
|
---|
2425 | /* Prompt heuristic comes from OpenSSH */
|
---|
2426 | strncpy(prompt + challengelen,
|
---|
2427 | memchr(prompt, '\n', challengelen) ?
|
---|
2428 | "": "\r\nResponse: ",
|
---|
2429 | (sizeof prompt) - challengelen);
|
---|
2430 | prompt[(sizeof prompt) - 1] = '\0';
|
---|
2431 | }
|
---|
2432 | }
|
---|
2433 | if (cfg.try_tis_auth &&
|
---|
2434 | (supported_auths_mask & (1 << SSH1_AUTH_CCARD)) &&
|
---|
2435 | !ccard_auth_refused) {
|
---|
2436 | pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE;
|
---|
2437 | logevent("Requested CryptoCard authentication");
|
---|
2438 | send_packet(SSH1_CMSG_AUTH_CCARD, PKT_END);
|
---|
2439 | crWaitUntil(ispkt);
|
---|
2440 | if (pktin.type != SSH1_SMSG_AUTH_CCARD_CHALLENGE) {
|
---|
2441 | logevent("CryptoCard authentication declined");
|
---|
2442 | c_write_str("CryptoCard authentication refused.\r\n");
|
---|
2443 | ccard_auth_refused = 1;
|
---|
2444 | continue;
|
---|
2445 | } else {
|
---|
2446 | int challengelen = ((pktin.body[0] << 24) |
|
---|
2447 | (pktin.body[1] << 16) |
|
---|
2448 | (pktin.body[2] << 8) |
|
---|
2449 | (pktin.body[3]));
|
---|
2450 | logevent("Received CryptoCard challenge");
|
---|
2451 | if (challengelen > sizeof(prompt) - 1)
|
---|
2452 | challengelen = sizeof(prompt) - 1; /* prevent overrun */
|
---|
2453 | memcpy(prompt, pktin.body + 4, challengelen);
|
---|
2454 | strncpy(prompt + challengelen,
|
---|
2455 | memchr(prompt, '\n', challengelen) ?
|
---|
2456 | "" : "\r\nResponse: ",
|
---|
2457 | sizeof(prompt) - challengelen);
|
---|
2458 | prompt[sizeof(prompt) - 1] = '\0';
|
---|
2459 | }
|
---|
2460 | }
|
---|
2461 | if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {
|
---|
2462 | sprintf(prompt, "%.90s@%.90s's password: ",
|
---|
2463 | username, savedhost);
|
---|
2464 | }
|
---|
2465 | if (pwpkt_type == SSH1_CMSG_AUTH_RSA) {
|
---|
2466 | char *comment = NULL;
|
---|
2467 | int type;
|
---|
2468 | char msgbuf[256];
|
---|
2469 | if (flags & FLAG_VERBOSE)
|
---|
2470 | c_write_str("Trying public key authentication.\r\n");
|
---|
2471 | sprintf(msgbuf, "Trying public key \"%.200s\"", cfg.keyfile);
|
---|
2472 | logevent(msgbuf);
|
---|
2473 | type = key_type(cfg.keyfile);
|
---|
2474 | if (type != SSH_KEYTYPE_SSH1) {
|
---|
2475 | sprintf(msgbuf, "Key is of wrong type (%s)",
|
---|
2476 | key_type_to_str(type));
|
---|
2477 | logevent(msgbuf);
|
---|
2478 | c_write_str(msgbuf);
|
---|
2479 | c_write_str("\r\n");
|
---|
2480 | tried_publickey = 1;
|
---|
2481 | continue;
|
---|
2482 | }
|
---|
2483 | sprintf(prompt, "Passphrase for key \"%.100s\": ", comment);
|
---|
2484 | sfree(comment);
|
---|
2485 | }
|
---|
2486 |
|
---|
2487 | /*
|
---|
2488 | * Show password prompt, having first obtained it via a TIS
|
---|
2489 | * or CryptoCard exchange if we're doing TIS or CryptoCard
|
---|
2490 | * authentication.
|
---|
2491 | */
|
---|
2492 | assert(ssh_get_line);
|
---|
2493 |
|
---|
2494 | if (!ssh_get_line(prompt, password, sizeof(password), TRUE)) {
|
---|
2495 | /*
|
---|
2496 | * get_line failed to get a password (for example
|
---|
2497 | * because one was supplied on the command line
|
---|
2498 | * which has already failed to work). Terminate.
|
---|
2499 | */
|
---|
2500 | send_packet(SSH1_MSG_DISCONNECT,
|
---|
2501 | PKT_STR, "No more passwords available to try",
|
---|
2502 | PKT_END);
|
---|
2503 | connection_fatal("Unable to authenticate");
|
---|
2504 | ssh_state = SSH_STATE_CLOSED;
|
---|
2505 | crReturn(1);
|
---|
2506 | }
|
---|
2507 |
|
---|
2508 | if (pwpkt_type == SSH1_CMSG_AUTH_RSA) {
|
---|
2509 | /*
|
---|
2510 | * Try public key authentication with the specified
|
---|
2511 | * key file.
|
---|
2512 | */
|
---|
2513 | static struct RSAKey pubkey;
|
---|
2514 | static Bignum challenge, response;
|
---|
2515 | static int i;
|
---|
2516 | static unsigned char buffer[32];
|
---|
2517 |
|
---|
2518 | tried_publickey = 1;
|
---|
2519 | i = loadrsakey(cfg.keyfile, &pubkey, password);
|
---|
2520 | if (i == 0) {
|
---|
2521 | c_write_str("Couldn't load private key from ");
|
---|
2522 | c_write_str(cfg.keyfile);
|
---|
2523 | c_write_str(".\r\n");
|
---|
2524 | continue; /* go and try password */
|
---|
2525 | }
|
---|
2526 | if (i == -1) {
|
---|
2527 | c_write_str("Wrong passphrase.\r\n");
|
---|
2528 | tried_publickey = 0;
|
---|
2529 | continue; /* try again */
|
---|
2530 | }
|
---|
2531 |
|
---|
2532 | /*
|
---|
2533 | * Send a public key attempt.
|
---|
2534 | */
|
---|
2535 | send_packet(SSH1_CMSG_AUTH_RSA,
|
---|
2536 | PKT_BIGNUM, pubkey.modulus, PKT_END);
|
---|
2537 |
|
---|
2538 | crWaitUntil(ispkt);
|
---|
2539 | if (pktin.type == SSH1_SMSG_FAILURE) {
|
---|
2540 | c_write_str("Server refused our public key.\r\n");
|
---|
2541 | continue; /* go and try password */
|
---|
2542 | }
|
---|
2543 | if (pktin.type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
|
---|
2544 | bombout(("Bizarre response to offer of public key"));
|
---|
2545 | crReturn(0);
|
---|
2546 | }
|
---|
2547 | ssh1_read_bignum(pktin.body, &challenge);
|
---|
2548 | response = rsadecrypt(challenge, &pubkey);
|
---|
2549 | freebn(pubkey.private_exponent); /* burn the evidence */
|
---|
2550 |
|
---|
2551 | for (i = 0; i < 32; i++) {
|
---|
2552 | buffer[i] = bignum_byte(response, 31 - i);
|
---|
2553 | }
|
---|
2554 |
|
---|
2555 | MD5Init(&md5c);
|
---|
2556 | MD5Update(&md5c, buffer, 32);
|
---|
2557 | MD5Update(&md5c, session_id, 16);
|
---|
2558 | MD5Final(buffer, &md5c);
|
---|
2559 |
|
---|
2560 | send_packet(SSH1_CMSG_AUTH_RSA_RESPONSE,
|
---|
2561 | PKT_DATA, buffer, 16, PKT_END);
|
---|
2562 |
|
---|
2563 | crWaitUntil(ispkt);
|
---|
2564 | if (pktin.type == SSH1_SMSG_FAILURE) {
|
---|
2565 | if (flags & FLAG_VERBOSE)
|
---|
2566 | c_write_str
|
---|
2567 | ("Failed to authenticate with our public key.\r\n");
|
---|
2568 | continue; /* go and try password */
|
---|
2569 | } else if (pktin.type != SSH1_SMSG_SUCCESS) {
|
---|
2570 | bombout(
|
---|
2571 | ("Bizarre response to RSA authentication response"));
|
---|
2572 | crReturn(0);
|
---|
2573 | }
|
---|
2574 |
|
---|
2575 | break; /* we're through! */
|
---|
2576 | } else {
|
---|
2577 | if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {
|
---|
2578 | /*
|
---|
2579 | * Defence against traffic analysis: we send a
|
---|
2580 | * whole bunch of packets containing strings of
|
---|
2581 | * different lengths. One of these strings is the
|
---|
2582 | * password, in a SSH1_CMSG_AUTH_PASSWORD packet.
|
---|
2583 | * The others are all random data in
|
---|
2584 | * SSH1_MSG_IGNORE packets. This way a passive
|
---|
2585 | * listener can't tell which is the password, and
|
---|
2586 | * hence can't deduce the password length.
|
---|
2587 | *
|
---|
2588 | * Anybody with a password length greater than 16
|
---|
2589 | * bytes is going to have enough entropy in their
|
---|
2590 | * password that a listener won't find it _that_
|
---|
2591 | * much help to know how long it is. So what we'll
|
---|
2592 | * do is:
|
---|
2593 | *
|
---|
2594 | * - if password length < 16, we send 15 packets
|
---|
2595 | * containing string lengths 1 through 15
|
---|
2596 | *
|
---|
2597 | * - otherwise, we let N be the nearest multiple
|
---|
2598 | * of 8 below the password length, and send 8
|
---|
2599 | * packets containing string lengths N through
|
---|
2600 | * N+7. This won't obscure the order of
|
---|
2601 | * magnitude of the password length, but it will
|
---|
2602 | * introduce a bit of extra uncertainty.
|
---|
2603 | *
|
---|
2604 | * A few servers (the old 1.2.18 through 1.2.22)
|
---|
2605 | * can't deal with SSH1_MSG_IGNORE. For these
|
---|
2606 | * servers, we need an alternative defence. We make
|
---|
2607 | * use of the fact that the password is interpreted
|
---|
2608 | * as a C string: so we can append a NUL, then some
|
---|
2609 | * random data.
|
---|
2610 | *
|
---|
2611 | * One server (a Cisco one) can deal with neither
|
---|
2612 | * SSH1_MSG_IGNORE _nor_ a padded password string.
|
---|
2613 | * For this server we are left with no defences
|
---|
2614 | * against password length sniffing.
|
---|
2615 | */
|
---|
2616 | if (!(ssh_remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE)) {
|
---|
2617 | /*
|
---|
2618 | * The server can deal with SSH1_MSG_IGNORE, so
|
---|
2619 | * we can use the primary defence.
|
---|
2620 | */
|
---|
2621 | int bottom, top, pwlen, i;
|
---|
2622 | char *randomstr;
|
---|
2623 |
|
---|
2624 | pwlen = strlen(password);
|
---|
2625 | if (pwlen < 16) {
|
---|
2626 | bottom = 0; /* zero length passwords are OK! :-) */
|
---|
2627 | top = 15;
|
---|
2628 | } else {
|
---|
2629 | bottom = pwlen & ~7;
|
---|
2630 | top = bottom + 7;
|
---|
2631 | }
|
---|
2632 |
|
---|
2633 | assert(pwlen >= bottom && pwlen <= top);
|
---|
2634 |
|
---|
2635 | randomstr = smalloc(top + 1);
|
---|
2636 |
|
---|
2637 | for (i = bottom; i <= top; i++) {
|
---|
2638 | if (i == pwlen)
|
---|
2639 | defer_packet(pwpkt_type, PKT_STR, password,
|
---|
2640 | PKT_END);
|
---|
2641 | else {
|
---|
2642 | for (j = 0; j < i; j++) {
|
---|
2643 | do {
|
---|
2644 | randomstr[j] = random_byte();
|
---|
2645 | } while (randomstr[j] == '\0');
|
---|
2646 | }
|
---|
2647 | randomstr[i] = '\0';
|
---|
2648 | defer_packet(SSH1_MSG_IGNORE,
|
---|
2649 | PKT_STR, randomstr, PKT_END);
|
---|
2650 | }
|
---|
2651 | }
|
---|
2652 | logevent("Sending password with camouflage packets");
|
---|
2653 | ssh_pkt_defersend();
|
---|
2654 | }
|
---|
2655 | else if (!(ssh_remote_bugs & BUG_NEEDS_SSH1_PLAIN_PASSWORD)) {
|
---|
2656 | /*
|
---|
2657 | * The server can't deal with SSH1_MSG_IGNORE
|
---|
2658 | * but can deal with padded passwords, so we
|
---|
2659 | * can use the secondary defence.
|
---|
2660 | */
|
---|
2661 | char string[64];
|
---|
2662 | char *s;
|
---|
2663 | int len;
|
---|
2664 |
|
---|
2665 | len = strlen(password);
|
---|
2666 | if (len < sizeof(string)) {
|
---|
2667 | s = string;
|
---|
2668 | strcpy(string, password);
|
---|
2669 | len++; /* cover the zero byte */
|
---|
2670 | while (len < sizeof(string)) {
|
---|
2671 | string[len++] = (char) random_byte();
|
---|
2672 | }
|
---|
2673 | } else {
|
---|
2674 | s = password;
|
---|
2675 | }
|
---|
2676 | logevent("Sending length-padded password");
|
---|
2677 | send_packet(pwpkt_type, PKT_INT, len,
|
---|
2678 | PKT_DATA, s, len, PKT_END);
|
---|
2679 | } else {
|
---|
2680 | /*
|
---|
2681 | * The server has _both_
|
---|
2682 | * BUG_CHOKES_ON_SSH1_IGNORE and
|
---|
2683 | * BUG_NEEDS_SSH1_PLAIN_PASSWORD. There is
|
---|
2684 | * therefore nothing we can do.
|
---|
2685 | */
|
---|
2686 | int len;
|
---|
2687 | len = strlen(password);
|
---|
2688 | logevent("Sending unpadded password");
|
---|
2689 | send_packet(pwpkt_type, PKT_INT, len,
|
---|
2690 | PKT_DATA, password, len, PKT_END);
|
---|
2691 | }
|
---|
2692 | } else {
|
---|
2693 | send_packet(pwpkt_type, PKT_STR, password, PKT_END);
|
---|
2694 | }
|
---|
2695 | }
|
---|
2696 | logevent("Sent password");
|
---|
2697 | memset(password, 0, strlen(password));
|
---|
2698 | crWaitUntil(ispkt);
|
---|
2699 | if (pktin.type == SSH1_SMSG_FAILURE) {
|
---|
2700 | if (flags & FLAG_VERBOSE)
|
---|
2701 | c_write_str("Access denied\r\n");
|
---|
2702 | logevent("Authentication refused");
|
---|
2703 | } else if (pktin.type == SSH1_MSG_DISCONNECT) {
|
---|
2704 | logevent("Received disconnect request");
|
---|
2705 | ssh_state = SSH_STATE_CLOSED;
|
---|
2706 | crReturn(1);
|
---|
2707 | } else if (pktin.type != SSH1_SMSG_SUCCESS) {
|
---|
2708 | bombout(("Strange packet received, type %d", pktin.type));
|
---|
2709 | crReturn(0);
|
---|
2710 | }
|
---|
2711 | }
|
---|
2712 |
|
---|
2713 | logevent("Authentication successful");
|
---|
2714 |
|
---|
2715 | crFinish(1);
|
---|
2716 | }
|
---|
2717 |
|
---|
2718 | void sshfwd_close(struct ssh_channel *c)
|
---|
2719 | {
|
---|
2720 | if (c && !c->closes) {
|
---|
2721 | /*
|
---|
2722 | * If the channel's remoteid is -1, we have sent
|
---|
2723 | * CHANNEL_OPEN for this channel, but it hasn't even been
|
---|
2724 | * acknowledged by the server. So we must set a close flag
|
---|
2725 | * on it now, and then when the server acks the channel
|
---|
2726 | * open, we can close it then.
|
---|
2727 | */
|
---|
2728 | if ((int)c->remoteid != -1) {
|
---|
2729 | if (ssh_version == 1) {
|
---|
2730 | send_packet(SSH1_MSG_CHANNEL_CLOSE, PKT_INT, c->remoteid,
|
---|
2731 | PKT_END);
|
---|
2732 | } else {
|
---|
2733 | ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE);
|
---|
2734 | ssh2_pkt_adduint32(c->remoteid);
|
---|
2735 | ssh2_pkt_send();
|
---|
2736 | }
|
---|
2737 | }
|
---|
2738 | c->closes = 1;
|
---|
2739 | if (c->type == CHAN_X11) {
|
---|
2740 | c->u.x11.s = NULL;
|
---|
2741 | logevent("Forwarded X11 connection terminated");
|
---|
2742 | } else if (c->type == CHAN_SOCKDATA ||
|
---|
2743 | c->type == CHAN_SOCKDATA_DORMANT) {
|
---|
2744 | c->u.pfd.s = NULL;
|
---|
2745 | logevent("Forwarded port closed");
|
---|
2746 | }
|
---|
2747 | }
|
---|
2748 | }
|
---|
2749 |
|
---|
2750 | int sshfwd_write(struct ssh_channel *c, char *buf, int len)
|
---|
2751 | {
|
---|
2752 | if (ssh_version == 1) {
|
---|
2753 | send_packet(SSH1_MSG_CHANNEL_DATA,
|
---|
2754 | PKT_INT, c->remoteid,
|
---|
2755 | PKT_INT, len, PKT_DATA, buf, len, PKT_END);
|
---|
2756 | /*
|
---|
2757 | * In SSH1 we can return 0 here - implying that forwarded
|
---|
2758 | * connections are never individually throttled - because
|
---|
2759 | * the only circumstance that can cause throttling will be
|
---|
2760 | * the whole SSH connection backing up, in which case
|
---|
2761 | * _everything_ will be throttled as a whole.
|
---|
2762 | */
|
---|
2763 | return 0;
|
---|
2764 | } else {
|
---|
2765 | ssh2_add_channel_data(c, buf, len);
|
---|
2766 | return ssh2_try_send(c);
|
---|
2767 | }
|
---|
2768 | }
|
---|
2769 |
|
---|
2770 | void sshfwd_unthrottle(struct ssh_channel *c, int bufsize)
|
---|
2771 | {
|
---|
2772 | if (ssh_version == 1) {
|
---|
2773 | if (c->v.v1.throttling && bufsize < SSH1_BUFFER_LIMIT) {
|
---|
2774 | c->v.v1.throttling = 0;
|
---|
2775 | ssh1_throttle(-1);
|
---|
2776 | }
|
---|
2777 | } else {
|
---|
2778 | ssh2_set_window(c, OUR_V2_WINSIZE - bufsize);
|
---|
2779 | }
|
---|
2780 | }
|
---|
2781 |
|
---|
2782 | static void ssh1_protocol(unsigned char *in, int inlen, int ispkt)
|
---|
2783 | {
|
---|
2784 | crBegin;
|
---|
2785 |
|
---|
2786 | random_init();
|
---|
2787 |
|
---|
2788 | while (!do_ssh1_login(in, inlen, ispkt)) {
|
---|
2789 | crReturnV;
|
---|
2790 | }
|
---|
2791 | if (ssh_state == SSH_STATE_CLOSED)
|
---|
2792 | crReturnV;
|
---|
2793 |
|
---|
2794 | if (cfg.agentfwd && agent_exists()) {
|
---|
2795 | logevent("Requesting agent forwarding");
|
---|
2796 | send_packet(SSH1_CMSG_AGENT_REQUEST_FORWARDING, PKT_END);
|
---|
2797 | do {
|
---|
2798 | crReturnV;
|
---|
2799 | } while (!ispkt);
|
---|
2800 | if (pktin.type != SSH1_SMSG_SUCCESS
|
---|
2801 | && pktin.type != SSH1_SMSG_FAILURE) {
|
---|
2802 | bombout(("Protocol confusion"));
|
---|
2803 | crReturnV;
|
---|
2804 | } else if (pktin.type == SSH1_SMSG_FAILURE) {
|
---|
2805 | logevent("Agent forwarding refused");
|
---|
2806 | } else {
|
---|
2807 | logevent("Agent forwarding enabled");
|
---|
2808 | ssh_agentfwd_enabled = TRUE;
|
---|
2809 | }
|
---|
2810 | }
|
---|
2811 |
|
---|
2812 | if (!cfg.nopty) {
|
---|
2813 | send_packet(SSH1_CMSG_REQUEST_PTY,
|
---|
2814 | PKT_STR, cfg.termtype,
|
---|
2815 | PKT_INT, rows, PKT_INT, cols,
|
---|
2816 | PKT_INT, 0, PKT_INT, 0, PKT_CHAR, 0, PKT_END);
|
---|
2817 | ssh_state = SSH_STATE_INTERMED;
|
---|
2818 | do {
|
---|
2819 | crReturnV;
|
---|
2820 | } while (!ispkt);
|
---|
2821 | if (pktin.type != SSH1_SMSG_SUCCESS
|
---|
2822 | && pktin.type != SSH1_SMSG_FAILURE) {
|
---|
2823 | bombout(("Protocol confusion"));
|
---|
2824 | crReturnV;
|
---|
2825 | } else if (pktin.type == SSH1_SMSG_FAILURE) {
|
---|
2826 | c_write_str("Server refused to allocate pty\r\n");
|
---|
2827 | ssh_editing = ssh_echoing = 1;
|
---|
2828 | }
|
---|
2829 | logevent("Allocated pty");
|
---|
2830 | } else {
|
---|
2831 | ssh_editing = ssh_echoing = 1;
|
---|
2832 | }
|
---|
2833 |
|
---|
2834 | if (cfg.compression) {
|
---|
2835 | send_packet(SSH1_CMSG_REQUEST_COMPRESSION, PKT_INT, 6, PKT_END);
|
---|
2836 | do {
|
---|
2837 | crReturnV;
|
---|
2838 | } while (!ispkt);
|
---|
2839 | if (pktin.type != SSH1_SMSG_SUCCESS
|
---|
2840 | && pktin.type != SSH1_SMSG_FAILURE) {
|
---|
2841 | bombout(("Protocol confusion"));
|
---|
2842 | crReturnV;
|
---|
2843 | } else if (pktin.type == SSH1_SMSG_FAILURE) {
|
---|
2844 | c_write_str("Server refused to compress\r\n");
|
---|
2845 | }
|
---|
2846 | logevent("Started compression");
|
---|
2847 | ssh1_compressing = TRUE;
|
---|
2848 | zlib_compress_init();
|
---|
2849 | zlib_decompress_init();
|
---|
2850 | }
|
---|
2851 |
|
---|
2852 | /*
|
---|
2853 | * Start the shell or command.
|
---|
2854 | *
|
---|
2855 | * Special case: if the first-choice command is an SSH2
|
---|
2856 | * subsystem (hence not usable here) and the second choice
|
---|
2857 | * exists, we fall straight back to that.
|
---|
2858 | */
|
---|
2859 | {
|
---|
2860 | char *cmd = cfg.remote_cmd_ptr;
|
---|
2861 |
|
---|
2862 | if (cfg.ssh_subsys && cfg.remote_cmd_ptr2) {
|
---|
2863 | cmd = cfg.remote_cmd_ptr2;
|
---|
2864 | ssh_fallback_cmd = TRUE;
|
---|
2865 | }
|
---|
2866 | if (*cmd)
|
---|
2867 | send_packet(SSH1_CMSG_EXEC_CMD, PKT_STR, cmd, PKT_END);
|
---|
2868 | else
|
---|
2869 | send_packet(SSH1_CMSG_EXEC_SHELL, PKT_END);
|
---|
2870 | logevent("Started session");
|
---|
2871 | }
|
---|
2872 |
|
---|
2873 | ssh_state = SSH_STATE_SESSION;
|
---|
2874 | if (size_needed)
|
---|
2875 | ssh_size();
|
---|
2876 | if (eof_needed)
|
---|
2877 | ssh_special(TS_EOF);
|
---|
2878 |
|
---|
2879 | ldisc_send(NULL, 0, 0); /* cause ldisc to notice changes */
|
---|
2880 | ssh_send_ok = 1;
|
---|
2881 | ssh_channels = newtree234(ssh_channelcmp);
|
---|
2882 | while (1) {
|
---|
2883 | crReturnV;
|
---|
2884 | if (ispkt) {
|
---|
2885 | if (pktin.type == SSH1_SMSG_STDOUT_DATA ||
|
---|
2886 | pktin.type == SSH1_SMSG_STDERR_DATA) {
|
---|
2887 | long len = GET_32BIT(pktin.body);
|
---|
2888 | int bufsize =
|
---|
2889 | from_backend(pktin.type == SSH1_SMSG_STDERR_DATA,
|
---|
2890 | pktin.body + 4, len);
|
---|
2891 | if (!ssh1_stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) {
|
---|
2892 | ssh1_stdout_throttling = 1;
|
---|
2893 | ssh1_throttle(+1);
|
---|
2894 | }
|
---|
2895 | } else if (pktin.type == SSH1_MSG_DISCONNECT) {
|
---|
2896 | ssh_state = SSH_STATE_CLOSED;
|
---|
2897 | logevent("Received disconnect request");
|
---|
2898 | crReturnV;
|
---|
2899 | } else if (pktin.type == SSH1_SMSG_X11_OPEN) {
|
---|
2900 | /* Remote side is trying to open a channel to talk to our
|
---|
2901 | * X-Server. Give them back a local channel number. */
|
---|
2902 |
|
---|
2903 | logevent("Received X11 connect request");
|
---|
2904 | /* Refuse if X11 forwarding is disabled. */
|
---|
2905 | send_packet(SSH1_MSG_CHANNEL_OPEN_FAILURE,
|
---|
2906 | PKT_INT, GET_32BIT(pktin.body), PKT_END);
|
---|
2907 | logevent("Rejected X11 connect request");
|
---|
2908 |
|
---|
2909 | } else if (pktin.type == SSH1_SMSG_AGENT_OPEN) {
|
---|
2910 | /* Remote side is trying to open a channel to talk to our
|
---|
2911 | * agent. Give them back a local channel number. */
|
---|
2912 |
|
---|
2913 | /* Refuse if agent forwarding is disabled. */
|
---|
2914 | send_packet(SSH1_MSG_CHANNEL_OPEN_FAILURE,
|
---|
2915 | PKT_INT, GET_32BIT(pktin.body), PKT_END);
|
---|
2916 |
|
---|
2917 | } else if (pktin.type == SSH1_MSG_PORT_OPEN) {
|
---|
2918 | /* Remote side is trying to open a channel to talk to a
|
---|
2919 | * forwarded port. Give them back a local channel number. */
|
---|
2920 | struct ssh_channel *c;
|
---|
2921 | struct ssh_rportfwd pf;
|
---|
2922 | int hostsize, port;
|
---|
2923 | char host[256];
|
---|
2924 | char *p, *h;
|
---|
2925 | c = smalloc(sizeof(struct ssh_channel));
|
---|
2926 |
|
---|
2927 | hostsize = GET_32BIT(pktin.body+4);
|
---|
2928 | for(h = host, p = pktin.body+8; hostsize != 0; hostsize--) {
|
---|
2929 | if (h+1 < host+sizeof(host))
|
---|
2930 | *h++ = *p;
|
---|
2931 | p++;
|
---|
2932 | }
|
---|
2933 | *h = 0;
|
---|
2934 | port = GET_32BIT(p);
|
---|
2935 |
|
---|
2936 | strcpy(pf.dhost, host);
|
---|
2937 | pf.dport = port;
|
---|
2938 |
|
---|
2939 | } else if (pktin.type == SSH1_MSG_CHANNEL_OPEN_CONFIRMATION) {
|
---|
2940 | unsigned int remoteid = GET_32BIT(pktin.body);
|
---|
2941 | unsigned int localid = GET_32BIT(pktin.body+4);
|
---|
2942 | struct ssh_channel *c;
|
---|
2943 |
|
---|
2944 | c = find234(ssh_channels, &remoteid, ssh_channelfind);
|
---|
2945 | if (c && c->type == CHAN_SOCKDATA_DORMANT) {
|
---|
2946 | c->remoteid = localid;
|
---|
2947 | c->type = CHAN_SOCKDATA;
|
---|
2948 | c->v.v1.throttling = 0;
|
---|
2949 | pfd_confirm(c->u.pfd.s);
|
---|
2950 | }
|
---|
2951 |
|
---|
2952 | if (c && c->closes) {
|
---|
2953 | /*
|
---|
2954 | * We have a pending close on this channel,
|
---|
2955 | * which we decided on before the server acked
|
---|
2956 | * the channel open. So now we know the
|
---|
2957 | * remoteid, we can close it again.
|
---|
2958 | */
|
---|
2959 | send_packet(SSH1_MSG_CHANNEL_CLOSE, PKT_INT, c->remoteid,
|
---|
2960 | PKT_END);
|
---|
2961 | }
|
---|
2962 |
|
---|
2963 | } else if (pktin.type == SSH1_MSG_CHANNEL_OPEN_FAILURE) {
|
---|
2964 | unsigned int remoteid = GET_32BIT(pktin.body);
|
---|
2965 | unsigned int localid = GET_32BIT(pktin.body+4);
|
---|
2966 | struct ssh_channel *c;
|
---|
2967 |
|
---|
2968 | c = find234(ssh_channels, &remoteid, ssh_channelfind);
|
---|
2969 | if (c && c->type == CHAN_SOCKDATA_DORMANT) {
|
---|
2970 | logevent("Forwarded connection refused by server");
|
---|
2971 | pfd_close(c->u.pfd.s);
|
---|
2972 | del234(ssh_channels, c);
|
---|
2973 | sfree(c);
|
---|
2974 | }
|
---|
2975 |
|
---|
2976 | } else if (pktin.type == SSH1_MSG_CHANNEL_CLOSE ||
|
---|
2977 | pktin.type == SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION) {
|
---|
2978 | /* Remote side closes a channel. */
|
---|
2979 | unsigned i = GET_32BIT(pktin.body);
|
---|
2980 | struct ssh_channel *c;
|
---|
2981 | c = find234(ssh_channels, &i, ssh_channelfind);
|
---|
2982 | if (c) {
|
---|
2983 | int closetype;
|
---|
2984 | closetype =
|
---|
2985 | (pktin.type == SSH1_MSG_CHANNEL_CLOSE ? 1 : 2);
|
---|
2986 | if (!(c->closes & closetype))
|
---|
2987 | send_packet(pktin.type, PKT_INT, c->remoteid,
|
---|
2988 | PKT_END);
|
---|
2989 | if ((c->closes == 0) && (c->type == CHAN_X11)) {
|
---|
2990 | logevent("Forwarded X11 connection terminated");
|
---|
2991 | assert(c->u.x11.s != NULL);
|
---|
2992 | // x11_close(c->u.x11.s);
|
---|
2993 | c->u.x11.s = NULL;
|
---|
2994 | }
|
---|
2995 | if ((c->closes == 0) && (c->type == CHAN_SOCKDATA)) {
|
---|
2996 | logevent("Forwarded port closed");
|
---|
2997 | assert(c->u.pfd.s != NULL);
|
---|
2998 | pfd_close(c->u.pfd.s);
|
---|
2999 | c->u.pfd.s = NULL;
|
---|
3000 | }
|
---|
3001 | c->closes |= closetype;
|
---|
3002 | if (c->closes == 3) {
|
---|
3003 | del234(ssh_channels, c);
|
---|
3004 | sfree(c);
|
---|
3005 | }
|
---|
3006 | }
|
---|
3007 | } else if (pktin.type == SSH1_MSG_CHANNEL_DATA) {
|
---|
3008 | /* Data sent down one of our channels. */
|
---|
3009 | int i = GET_32BIT(pktin.body);
|
---|
3010 | int len = GET_32BIT(pktin.body + 4);
|
---|
3011 | unsigned char *p = pktin.body + 8;
|
---|
3012 | struct ssh_channel *c;
|
---|
3013 | c = find234(ssh_channels, &i, ssh_channelfind);
|
---|
3014 | if (c) {
|
---|
3015 | int bufsize;
|
---|
3016 | switch (c->type) {
|
---|
3017 | case CHAN_X11:
|
---|
3018 | // bufsize = x11_send(c->u.x11.s, p, len);
|
---|
3019 | break;
|
---|
3020 | case CHAN_SOCKDATA:
|
---|
3021 | bufsize = pfd_send(c->u.pfd.s, p, len);
|
---|
3022 | break;
|
---|
3023 | case CHAN_AGENT:
|
---|
3024 | /* Data for an agent message. Buffer it. */
|
---|
3025 | while (len > 0) {
|
---|
3026 | if (c->u.a.lensofar < 4) {
|
---|
3027 | int l = min(4 - c->u.a.lensofar, len);
|
---|
3028 | memcpy(c->u.a.msglen + c->u.a.lensofar, p,
|
---|
3029 | l);
|
---|
3030 | p += l;
|
---|
3031 | len -= l;
|
---|
3032 | c->u.a.lensofar += l;
|
---|
3033 | }
|
---|
3034 | if (c->u.a.lensofar == 4) {
|
---|
3035 | c->u.a.totallen =
|
---|
3036 | 4 + GET_32BIT(c->u.a.msglen);
|
---|
3037 | c->u.a.message = smalloc(c->u.a.totallen);
|
---|
3038 | memcpy(c->u.a.message, c->u.a.msglen, 4);
|
---|
3039 | }
|
---|
3040 | if (c->u.a.lensofar >= 4 && len > 0) {
|
---|
3041 | int l =
|
---|
3042 | min(c->u.a.totallen - c->u.a.lensofar,
|
---|
3043 | len);
|
---|
3044 | memcpy(c->u.a.message + c->u.a.lensofar, p,
|
---|
3045 | l);
|
---|
3046 | p += l;
|
---|
3047 | len -= l;
|
---|
3048 | c->u.a.lensofar += l;
|
---|
3049 | }
|
---|
3050 | if (c->u.a.lensofar == c->u.a.totallen) {
|
---|
3051 | void *reply, *sentreply;
|
---|
3052 | int replylen;
|
---|
3053 | agent_query(c->u.a.message,
|
---|
3054 | c->u.a.totallen, &reply,
|
---|
3055 | &replylen);
|
---|
3056 | if (reply)
|
---|
3057 | sentreply = reply;
|
---|
3058 | else {
|
---|
3059 | /* Fake SSH_AGENT_FAILURE. */
|
---|
3060 | sentreply = "\0\0\0\1\5";
|
---|
3061 | replylen = 5;
|
---|
3062 | }
|
---|
3063 | send_packet(SSH1_MSG_CHANNEL_DATA,
|
---|
3064 | PKT_INT, c->remoteid,
|
---|
3065 | PKT_INT, replylen,
|
---|
3066 | PKT_DATA, sentreply, replylen,
|
---|
3067 | PKT_END);
|
---|
3068 | if (reply)
|
---|
3069 | sfree(reply);
|
---|
3070 | sfree(c->u.a.message);
|
---|
3071 | c->u.a.lensofar = 0;
|
---|
3072 | }
|
---|
3073 | }
|
---|
3074 | bufsize = 0; /* agent channels never back up */
|
---|
3075 | break;
|
---|
3076 | }
|
---|
3077 | if (!c->v.v1.throttling && bufsize > SSH1_BUFFER_LIMIT) {
|
---|
3078 | c->v.v1.throttling = 1;
|
---|
3079 | ssh1_throttle(+1);
|
---|
3080 | }
|
---|
3081 | }
|
---|
3082 | } else if (pktin.type == SSH1_SMSG_SUCCESS) {
|
---|
3083 | /* may be from EXEC_SHELL on some servers */
|
---|
3084 | } else if (pktin.type == SSH1_SMSG_FAILURE) {
|
---|
3085 | /* may be from EXEC_SHELL on some servers
|
---|
3086 | * if no pty is available or in other odd cases. Ignore */
|
---|
3087 | } else if (pktin.type == SSH1_SMSG_EXIT_STATUS) {
|
---|
3088 | char buf[100];
|
---|
3089 | ssh_exitcode = GET_32BIT(pktin.body);
|
---|
3090 | sprintf(buf, "Server sent command exit status %d",
|
---|
3091 | ssh_exitcode);
|
---|
3092 | logevent(buf);
|
---|
3093 | send_packet(SSH1_CMSG_EXIT_CONFIRMATION, PKT_END);
|
---|
3094 | /*
|
---|
3095 | * In case `helpful' firewalls or proxies tack
|
---|
3096 | * extra human-readable text on the end of the
|
---|
3097 | * session which we might mistake for another
|
---|
3098 | * encrypted packet, we close the session once
|
---|
3099 | * we've sent EXIT_CONFIRMATION.
|
---|
3100 | */
|
---|
3101 | ssh_state = SSH_STATE_CLOSED;
|
---|
3102 | crReturnV;
|
---|
3103 | } else {
|
---|
3104 | bombout(("Strange packet received: type %d", pktin.type));
|
---|
3105 | crReturnV;
|
---|
3106 | }
|
---|
3107 | } else {
|
---|
3108 | while (inlen > 0) {
|
---|
3109 | int len = min(inlen, 512);
|
---|
3110 | send_packet(SSH1_CMSG_STDIN_DATA,
|
---|
3111 | PKT_INT, len, PKT_DATA, in, len, PKT_END);
|
---|
3112 | in += len;
|
---|
3113 | inlen -= len;
|
---|
3114 | }
|
---|
3115 | }
|
---|
3116 | }
|
---|
3117 |
|
---|
3118 | crFinishV;
|
---|
3119 | }
|
---|
3120 |
|
---|
3121 | /*
|
---|
3122 | * Utility routine for decoding comma-separated strings in KEXINIT.
|
---|
3123 | */
|
---|
3124 | static int in_commasep_string(char *needle, char *haystack, int haylen)
|
---|
3125 | {
|
---|
3126 | int needlen = strlen(needle);
|
---|
3127 | while (1) {
|
---|
3128 | /*
|
---|
3129 | * Is it at the start of the string?
|
---|
3130 | */
|
---|
3131 | if (haylen >= needlen && /* haystack is long enough */
|
---|
3132 | !memcmp(needle, haystack, needlen) && /* initial match */
|
---|
3133 | (haylen == needlen || haystack[needlen] == ',')
|
---|
3134 | /* either , or EOS follows */
|
---|
3135 | )
|
---|
3136 | return 1;
|
---|
3137 | /*
|
---|
3138 | * If not, search for the next comma and resume after that.
|
---|
3139 | * If no comma found, terminate.
|
---|
3140 | */
|
---|
3141 | while (haylen > 0 && *haystack != ',')
|
---|
3142 | haylen--, haystack++;
|
---|
3143 | if (haylen == 0)
|
---|
3144 | return 0;
|
---|
3145 | haylen--, haystack++; /* skip over comma itself */
|
---|
3146 | }
|
---|
3147 | }
|
---|
3148 |
|
---|
3149 | /*
|
---|
3150 | * SSH2 key creation method.
|
---|
3151 | */
|
---|
3152 | static void ssh2_mkkey(Bignum K, char *H, char *sessid, char chr,
|
---|
3153 | char *keyspace)
|
---|
3154 | {
|
---|
3155 | SHA_State s;
|
---|
3156 | /* First 20 bytes. */
|
---|
3157 | SHA_Init(&s);
|
---|
3158 | if (!(ssh_remote_bugs & BUG_SSH2_DERIVEKEY))
|
---|
3159 | sha_mpint(&s, K);
|
---|
3160 | SHA_Bytes(&s, H, 20);
|
---|
3161 | SHA_Bytes(&s, &chr, 1);
|
---|
3162 | SHA_Bytes(&s, sessid, 20);
|
---|
3163 | SHA_Final(&s, keyspace);
|
---|
3164 | /* Next 20 bytes. */
|
---|
3165 | SHA_Init(&s);
|
---|
3166 | if (!(ssh_remote_bugs & BUG_SSH2_DERIVEKEY))
|
---|
3167 | sha_mpint(&s, K);
|
---|
3168 | SHA_Bytes(&s, H, 20);
|
---|
3169 | SHA_Bytes(&s, keyspace, 20);
|
---|
3170 | SHA_Final(&s, keyspace + 20);
|
---|
3171 | }
|
---|
3172 |
|
---|
3173 | /*
|
---|
3174 | * Handle the SSH2 transport layer.
|
---|
3175 | */
|
---|
3176 | static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt)
|
---|
3177 | {
|
---|
3178 | static int i, j, len, nbits, pbits, warn;
|
---|
3179 | static char *str;
|
---|
3180 | static Bignum p, g, e, f, K;
|
---|
3181 | static int kex_init_value, kex_reply_value;
|
---|
3182 | static const struct ssh_mac **maclist;
|
---|
3183 | static int nmacs;
|
---|
3184 | static const struct ssh2_cipher *cscipher_tobe = NULL;
|
---|
3185 | static const struct ssh2_cipher *sccipher_tobe = NULL;
|
---|
3186 | static const struct ssh_mac *csmac_tobe = NULL;
|
---|
3187 | static const struct ssh_mac *scmac_tobe = NULL;
|
---|
3188 | static const struct ssh_compress *cscomp_tobe = NULL;
|
---|
3189 | static const struct ssh_compress *sccomp_tobe = NULL;
|
---|
3190 | static char *hostkeydata, *sigdata, *keystr, *fingerprint;
|
---|
3191 | static int hostkeylen, siglen;
|
---|
3192 | static void *hkey; /* actual host key */
|
---|
3193 | static unsigned char exchange_hash[20];
|
---|
3194 | static unsigned char keyspace[40];
|
---|
3195 | static int n_preferred_ciphers;
|
---|
3196 | static const struct ssh2_ciphers *preferred_ciphers[CIPHER_MAX];
|
---|
3197 | static const struct ssh_compress *preferred_comp;
|
---|
3198 | static int cipherstr_started;
|
---|
3199 | static int first_kex;
|
---|
3200 |
|
---|
3201 | crBegin;
|
---|
3202 | random_init();
|
---|
3203 | first_kex = 1;
|
---|
3204 |
|
---|
3205 | /*
|
---|
3206 | * Set up the preferred ciphers. (NULL => warn below here)
|
---|
3207 | */
|
---|
3208 | n_preferred_ciphers = 0;
|
---|
3209 | for (i = 0; i < CIPHER_MAX; i++) {
|
---|
3210 | switch (cfg.ssh_cipherlist[i]) {
|
---|
3211 | case CIPHER_BLOWFISH:
|
---|
3212 | preferred_ciphers[n_preferred_ciphers] = &ssh2_blowfish;
|
---|
3213 | n_preferred_ciphers++;
|
---|
3214 | break;
|
---|
3215 | case CIPHER_DES:
|
---|
3216 | if (cfg.ssh2_des_cbc) {
|
---|
3217 | preferred_ciphers[n_preferred_ciphers] = &ssh2_des;
|
---|
3218 | n_preferred_ciphers++;
|
---|
3219 | }
|
---|
3220 | break;
|
---|
3221 | case CIPHER_3DES:
|
---|
3222 | preferred_ciphers[n_preferred_ciphers] = &ssh2_3des;
|
---|
3223 | n_preferred_ciphers++;
|
---|
3224 | break;
|
---|
3225 | case CIPHER_AES:
|
---|
3226 | preferred_ciphers[n_preferred_ciphers] = &ssh2_aes;
|
---|
3227 | n_preferred_ciphers++;
|
---|
3228 | break;
|
---|
3229 | case CIPHER_WARN:
|
---|
3230 | /* Flag for later. Don't bother if it's the last in
|
---|
3231 | * the list. */
|
---|
3232 | if (i < CIPHER_MAX - 1) {
|
---|
3233 | preferred_ciphers[n_preferred_ciphers] = NULL;
|
---|
3234 | n_preferred_ciphers++;
|
---|
3235 | }
|
---|
3236 | break;
|
---|
3237 | }
|
---|
3238 | }
|
---|
3239 |
|
---|
3240 | /*
|
---|
3241 | * Set up preferred compression.
|
---|
3242 | */
|
---|
3243 | if (cfg.compression)
|
---|
3244 | preferred_comp = &ssh_zlib;
|
---|
3245 | else
|
---|
3246 | preferred_comp = &ssh_comp_none;
|
---|
3247 |
|
---|
3248 | /*
|
---|
3249 | * Be prepared to work around the buggy MAC problem.
|
---|
3250 | */
|
---|
3251 | if (cfg.buggymac || (ssh_remote_bugs & BUG_SSH2_HMAC))
|
---|
3252 | maclist = buggymacs, nmacs = lenof(buggymacs);
|
---|
3253 | else
|
---|
3254 | maclist = macs, nmacs = lenof(macs);
|
---|
3255 |
|
---|
3256 | begin_key_exchange:
|
---|
3257 | /*
|
---|
3258 | * Construct and send our key exchange packet.
|
---|
3259 | */
|
---|
3260 | ssh2_pkt_init(SSH2_MSG_KEXINIT);
|
---|
3261 | for (i = 0; i < 16; i++)
|
---|
3262 | ssh2_pkt_addbyte((unsigned char) random_byte());
|
---|
3263 | /* List key exchange algorithms. */
|
---|
3264 | ssh2_pkt_addstring_start();
|
---|
3265 | for (i = 0; i < lenof(kex_algs); i++) {
|
---|
3266 | ssh2_pkt_addstring_str(kex_algs[i]->name);
|
---|
3267 | if (i < lenof(kex_algs) - 1)
|
---|
3268 | ssh2_pkt_addstring_str(",");
|
---|
3269 | }
|
---|
3270 | /* List server host key algorithms. */
|
---|
3271 | ssh2_pkt_addstring_start();
|
---|
3272 | for (i = 0; i < lenof(hostkey_algs); i++) {
|
---|
3273 | ssh2_pkt_addstring_str(hostkey_algs[i]->name);
|
---|
3274 | if (i < lenof(hostkey_algs) - 1)
|
---|
3275 | ssh2_pkt_addstring_str(",");
|
---|
3276 | }
|
---|
3277 | /* List client->server encryption algorithms. */
|
---|
3278 | ssh2_pkt_addstring_start();
|
---|
3279 | cipherstr_started = 0;
|
---|
3280 | for (i = 0; i < n_preferred_ciphers; i++) {
|
---|
3281 | const struct ssh2_ciphers *c = preferred_ciphers[i];
|
---|
3282 | if (!c) continue; /* warning flag */
|
---|
3283 | for (j = 0; j < c->nciphers; j++) {
|
---|
3284 | if (cipherstr_started)
|
---|
3285 | ssh2_pkt_addstring_str(",");
|
---|
3286 | ssh2_pkt_addstring_str(c->list[j]->name);
|
---|
3287 | cipherstr_started = 1;
|
---|
3288 | }
|
---|
3289 | }
|
---|
3290 | /* List server->client encryption algorithms. */
|
---|
3291 | ssh2_pkt_addstring_start();
|
---|
3292 | cipherstr_started = 0;
|
---|
3293 | for (i = 0; i < n_preferred_ciphers; i++) {
|
---|
3294 | const struct ssh2_ciphers *c = preferred_ciphers[i];
|
---|
3295 | if (!c) continue; /* warning flag */
|
---|
3296 | for (j = 0; j < c->nciphers; j++) {
|
---|
3297 | if (cipherstr_started)
|
---|
3298 | ssh2_pkt_addstring_str(",");
|
---|
3299 | ssh2_pkt_addstring_str(c->list[j]->name);
|
---|
3300 | cipherstr_started = 1;
|
---|
3301 | }
|
---|
3302 | }
|
---|
3303 | /* List client->server MAC algorithms. */
|
---|
3304 | ssh2_pkt_addstring_start();
|
---|
3305 | for (i = 0; i < nmacs; i++) {
|
---|
3306 | ssh2_pkt_addstring_str(maclist[i]->name);
|
---|
3307 | if (i < nmacs - 1)
|
---|
3308 | ssh2_pkt_addstring_str(",");
|
---|
3309 | }
|
---|
3310 | /* List server->client MAC algorithms. */
|
---|
3311 | ssh2_pkt_addstring_start();
|
---|
3312 | for (i = 0; i < nmacs; i++) {
|
---|
3313 | ssh2_pkt_addstring_str(maclist[i]->name);
|
---|
3314 | if (i < nmacs - 1)
|
---|
3315 | ssh2_pkt_addstring_str(",");
|
---|
3316 | }
|
---|
3317 | /* List client->server compression algorithms. */
|
---|
3318 | ssh2_pkt_addstring_start();
|
---|
3319 | for (i = 0; i < lenof(compressions) + 1; i++) {
|
---|
3320 | const struct ssh_compress *c =
|
---|
3321 | i == 0 ? preferred_comp : compressions[i - 1];
|
---|
3322 | ssh2_pkt_addstring_str(c->name);
|
---|
3323 | if (i < lenof(compressions))
|
---|
3324 | ssh2_pkt_addstring_str(",");
|
---|
3325 | }
|
---|
3326 | /* List server->client compression algorithms. */
|
---|
3327 | ssh2_pkt_addstring_start();
|
---|
3328 | for (i = 0; i < lenof(compressions) + 1; i++) {
|
---|
3329 | const struct ssh_compress *c =
|
---|
3330 | i == 0 ? preferred_comp : compressions[i - 1];
|
---|
3331 | ssh2_pkt_addstring_str(c->name);
|
---|
3332 | if (i < lenof(compressions))
|
---|
3333 | ssh2_pkt_addstring_str(",");
|
---|
3334 | }
|
---|
3335 | /* List client->server languages. Empty list. */
|
---|
3336 | ssh2_pkt_addstring_start();
|
---|
3337 | /* List server->client languages. Empty list. */
|
---|
3338 | ssh2_pkt_addstring_start();
|
---|
3339 | /* First KEX packet does _not_ follow, because we're not that brave. */
|
---|
3340 | ssh2_pkt_addbool(FALSE);
|
---|
3341 | /* Reserved. */
|
---|
3342 | ssh2_pkt_adduint32(0);
|
---|
3343 |
|
---|
3344 | exhash = exhashbase;
|
---|
3345 | sha_string(&exhash, pktout.data + 5, pktout.length - 5);
|
---|
3346 |
|
---|
3347 | ssh2_pkt_send();
|
---|
3348 |
|
---|
3349 | if (!ispkt)
|
---|
3350 | crWaitUntil(ispkt);
|
---|
3351 | sha_string(&exhash, pktin.data + 5, pktin.length - 5);
|
---|
3352 |
|
---|
3353 | /*
|
---|
3354 | * Now examine the other side's KEXINIT to see what we're up
|
---|
3355 | * to.
|
---|
3356 | */
|
---|
3357 | if (pktin.type != SSH2_MSG_KEXINIT) {
|
---|
3358 | bombout(("expected key exchange packet from server"));
|
---|
3359 | crReturn(0);
|
---|
3360 | }
|
---|
3361 | kex = NULL;
|
---|
3362 | hostkey = NULL;
|
---|
3363 | cscipher_tobe = NULL;
|
---|
3364 | sccipher_tobe = NULL;
|
---|
3365 | csmac_tobe = NULL;
|
---|
3366 | scmac_tobe = NULL;
|
---|
3367 | cscomp_tobe = NULL;
|
---|
3368 | sccomp_tobe = NULL;
|
---|
3369 | pktin.savedpos += 16; /* skip garbage cookie */
|
---|
3370 | ssh2_pkt_getstring(&str, &len); /* key exchange algorithms */
|
---|
3371 | for (i = 0; i < lenof(kex_algs); i++) {
|
---|
3372 | if (in_commasep_string(kex_algs[i]->name, str, len)) {
|
---|
3373 | kex = kex_algs[i];
|
---|
3374 | break;
|
---|
3375 | }
|
---|
3376 | }
|
---|
3377 | ssh2_pkt_getstring(&str, &len); /* host key algorithms */
|
---|
3378 | for (i = 0; i < lenof(hostkey_algs); i++) {
|
---|
3379 | if (in_commasep_string(hostkey_algs[i]->name, str, len)) {
|
---|
3380 | hostkey = hostkey_algs[i];
|
---|
3381 | break;
|
---|
3382 | }
|
---|
3383 | }
|
---|
3384 | ssh2_pkt_getstring(&str, &len); /* client->server cipher */
|
---|
3385 | warn = 0;
|
---|
3386 | for (i = 0; i < n_preferred_ciphers; i++) {
|
---|
3387 | const struct ssh2_ciphers *c = preferred_ciphers[i];
|
---|
3388 | if (!c) {
|
---|
3389 | warn = 1;
|
---|
3390 | } else {
|
---|
3391 | for (j = 0; j < c->nciphers; j++) {
|
---|
3392 | if (in_commasep_string(c->list[j]->name, str, len)) {
|
---|
3393 | cscipher_tobe = c->list[j];
|
---|
3394 | break;
|
---|
3395 | }
|
---|
3396 | }
|
---|
3397 | }
|
---|
3398 | if (cscipher_tobe) {
|
---|
3399 | if (warn)
|
---|
3400 | askcipher(cscipher_tobe->name, 1);
|
---|
3401 | break;
|
---|
3402 | }
|
---|
3403 | }
|
---|
3404 | if (!cscipher_tobe) {
|
---|
3405 | bombout(("Couldn't agree a client-to-server cipher (available: %s)", str));
|
---|
3406 | crReturn(0);
|
---|
3407 | }
|
---|
3408 |
|
---|
3409 | ssh2_pkt_getstring(&str, &len); /* server->client cipher */
|
---|
3410 | warn = 0;
|
---|
3411 | for (i = 0; i < n_preferred_ciphers; i++) {
|
---|
3412 | const struct ssh2_ciphers *c = preferred_ciphers[i];
|
---|
3413 | if (!c) {
|
---|
3414 | warn = 1;
|
---|
3415 | } else {
|
---|
3416 | for (j = 0; j < c->nciphers; j++) {
|
---|
3417 | if (in_commasep_string(c->list[j]->name, str, len)) {
|
---|
3418 | sccipher_tobe = c->list[j];
|
---|
3419 | break;
|
---|
3420 | }
|
---|
3421 | }
|
---|
3422 | }
|
---|
3423 | if (sccipher_tobe) {
|
---|
3424 | if (warn)
|
---|
3425 | askcipher(sccipher_tobe->name, 2);
|
---|
3426 | break;
|
---|
3427 | }
|
---|
3428 | }
|
---|
3429 | if (!sccipher_tobe) {
|
---|
3430 | bombout(("Couldn't agree a server-to-client cipher (available: %s)", str));
|
---|
3431 | crReturn(0);
|
---|
3432 | }
|
---|
3433 |
|
---|
3434 | ssh2_pkt_getstring(&str, &len); /* client->server mac */
|
---|
3435 | for (i = 0; i < nmacs; i++) {
|
---|
3436 | if (in_commasep_string(maclist[i]->name, str, len)) {
|
---|
3437 | csmac_tobe = maclist[i];
|
---|
3438 | break;
|
---|
3439 | }
|
---|
3440 | }
|
---|
3441 | ssh2_pkt_getstring(&str, &len); /* server->client mac */
|
---|
3442 | for (i = 0; i < nmacs; i++) {
|
---|
3443 | if (in_commasep_string(maclist[i]->name, str, len)) {
|
---|
3444 | scmac_tobe = maclist[i];
|
---|
3445 | break;
|
---|
3446 | }
|
---|
3447 | }
|
---|
3448 | ssh2_pkt_getstring(&str, &len); /* client->server compression */
|
---|
3449 | for (i = 0; i < lenof(compressions) + 1; i++) {
|
---|
3450 | const struct ssh_compress *c =
|
---|
3451 | i == 0 ? preferred_comp : compressions[i - 1];
|
---|
3452 | if (in_commasep_string(c->name, str, len)) {
|
---|
3453 | cscomp_tobe = c;
|
---|
3454 | break;
|
---|
3455 | }
|
---|
3456 | }
|
---|
3457 | ssh2_pkt_getstring(&str, &len); /* server->client compression */
|
---|
3458 | for (i = 0; i < lenof(compressions) + 1; i++) {
|
---|
3459 | const struct ssh_compress *c =
|
---|
3460 | i == 0 ? preferred_comp : compressions[i - 1];
|
---|
3461 | if (in_commasep_string(c->name, str, len)) {
|
---|
3462 | sccomp_tobe = c;
|
---|
3463 | break;
|
---|
3464 | }
|
---|
3465 | }
|
---|
3466 |
|
---|
3467 | /*
|
---|
3468 | * Work out the number of bits of key we will need from the key
|
---|
3469 | * exchange. We start with the maximum key length of either
|
---|
3470 | * cipher...
|
---|
3471 | */
|
---|
3472 | {
|
---|
3473 | int csbits, scbits;
|
---|
3474 |
|
---|
3475 | csbits = cscipher_tobe->keylen;
|
---|
3476 | scbits = sccipher_tobe->keylen;
|
---|
3477 | nbits = (csbits > scbits ? csbits : scbits);
|
---|
3478 | }
|
---|
3479 | /* The keys only have 160-bit entropy, since they're based on
|
---|
3480 | * a SHA-1 hash. So cap the key size at 160 bits. */
|
---|
3481 | if (nbits > 160)
|
---|
3482 | nbits = 160;
|
---|
3483 |
|
---|
3484 | /*
|
---|
3485 | * If we're doing Diffie-Hellman group exchange, start by
|
---|
3486 | * requesting a group.
|
---|
3487 | */
|
---|
3488 | if (kex == &ssh_diffiehellman_gex) {
|
---|
3489 | logevent("Doing Diffie-Hellman group exchange");
|
---|
3490 | ssh_pkt_ctx |= SSH2_PKTCTX_DHGEX;
|
---|
3491 | /*
|
---|
3492 | * Work out how big a DH group we will need to allow that
|
---|
3493 | * much data.
|
---|
3494 | */
|
---|
3495 | pbits = 512 << ((nbits - 1) / 64);
|
---|
3496 | ssh2_pkt_init(SSH2_MSG_KEX_DH_GEX_REQUEST);
|
---|
3497 | ssh2_pkt_adduint32(pbits);
|
---|
3498 | ssh2_pkt_send();
|
---|
3499 | crWaitUntil(ispkt);
|
---|
3500 | if (pktin.type != SSH2_MSG_KEX_DH_GEX_GROUP) {
|
---|
3501 | bombout(("expected key exchange group packet from server"));
|
---|
3502 | crReturn(0);
|
---|
3503 | }
|
---|
3504 | p = ssh2_pkt_getmp();
|
---|
3505 | g = ssh2_pkt_getmp();
|
---|
3506 | dh_setup_group(p, g);
|
---|
3507 | kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT;
|
---|
3508 | kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY;
|
---|
3509 | } else {
|
---|
3510 | ssh_pkt_ctx |= SSH2_PKTCTX_DHGROUP1;
|
---|
3511 | dh_setup_group1();
|
---|
3512 | kex_init_value = SSH2_MSG_KEXDH_INIT;
|
---|
3513 | kex_reply_value = SSH2_MSG_KEXDH_REPLY;
|
---|
3514 | }
|
---|
3515 |
|
---|
3516 | logevent("Doing Diffie-Hellman key exchange");
|
---|
3517 | /*
|
---|
3518 | * Now generate and send e for Diffie-Hellman.
|
---|
3519 | */
|
---|
3520 | e = dh_create_e(nbits * 2);
|
---|
3521 | ssh2_pkt_init(kex_init_value);
|
---|
3522 | ssh2_pkt_addmp(e);
|
---|
3523 | ssh2_pkt_send();
|
---|
3524 | crWaitUntil(ispkt);
|
---|
3525 | if (pktin.type != kex_reply_value) {
|
---|
3526 | bombout(("expected key exchange reply packet from server"));
|
---|
3527 | crReturn(0);
|
---|
3528 | }
|
---|
3529 | ssh2_pkt_getstring(&hostkeydata, &hostkeylen);
|
---|
3530 | f = ssh2_pkt_getmp();
|
---|
3531 | ssh2_pkt_getstring(&sigdata, &siglen);
|
---|
3532 |
|
---|
3533 | K = dh_find_K(f);
|
---|
3534 |
|
---|
3535 | sha_string(&exhash, hostkeydata, hostkeylen);
|
---|
3536 | if (kex == &ssh_diffiehellman_gex) {
|
---|
3537 | sha_uint32(&exhash, pbits);
|
---|
3538 | sha_mpint(&exhash, p);
|
---|
3539 | sha_mpint(&exhash, g);
|
---|
3540 | }
|
---|
3541 | sha_mpint(&exhash, e);
|
---|
3542 | sha_mpint(&exhash, f);
|
---|
3543 | sha_mpint(&exhash, K);
|
---|
3544 | SHA_Final(&exhash, exchange_hash);
|
---|
3545 |
|
---|
3546 | dh_cleanup();
|
---|
3547 | #if 0
|
---|
3548 | debug(("Exchange hash is:\n"));
|
---|
3549 | dmemdump(exchange_hash, 20);
|
---|
3550 | #endif
|
---|
3551 |
|
---|
3552 | hkey = hostkey->newkey(hostkeydata, hostkeylen);
|
---|
3553 | if (!hkey ||
|
---|
3554 | !hostkey->verifysig(hkey, sigdata, siglen, exchange_hash, 20)) {
|
---|
3555 | bombout(("Server's host key did not match the signature supplied"));
|
---|
3556 | crReturn(0);
|
---|
3557 | }
|
---|
3558 |
|
---|
3559 | /*
|
---|
3560 | * Authenticate remote host: verify host key. (We've already
|
---|
3561 | * checked the signature of the exchange hash.)
|
---|
3562 | */
|
---|
3563 | keystr = hostkey->fmtkey(hkey);
|
---|
3564 | fingerprint = hostkey->fingerprint(hkey);
|
---|
3565 | verify_ssh_host_key(savedhost, savedport, hostkey->keytype,
|
---|
3566 | keystr, fingerprint);
|
---|
3567 | if (first_kex) { /* don't bother logging this in rekeys */
|
---|
3568 | logevent("Host key fingerprint is:");
|
---|
3569 | logevent(fingerprint);
|
---|
3570 | }
|
---|
3571 | sfree(fingerprint);
|
---|
3572 | sfree(keystr);
|
---|
3573 | hostkey->freekey(hkey);
|
---|
3574 |
|
---|
3575 | /*
|
---|
3576 | * Send SSH2_MSG_NEWKEYS.
|
---|
3577 | */
|
---|
3578 | ssh2_pkt_init(SSH2_MSG_NEWKEYS);
|
---|
3579 | ssh2_pkt_send();
|
---|
3580 |
|
---|
3581 | /*
|
---|
3582 | * Expect SSH2_MSG_NEWKEYS from server.
|
---|
3583 | */
|
---|
3584 | crWaitUntil(ispkt);
|
---|
3585 | if (pktin.type != SSH2_MSG_NEWKEYS) {
|
---|
3586 | bombout(("expected new-keys packet from server"));
|
---|
3587 | crReturn(0);
|
---|
3588 | }
|
---|
3589 |
|
---|
3590 | /*
|
---|
3591 | * Create and initialise session keys.
|
---|
3592 | */
|
---|
3593 | cscipher = cscipher_tobe;
|
---|
3594 | sccipher = sccipher_tobe;
|
---|
3595 | csmac = csmac_tobe;
|
---|
3596 | scmac = scmac_tobe;
|
---|
3597 | cscomp = cscomp_tobe;
|
---|
3598 | sccomp = sccomp_tobe;
|
---|
3599 | cscomp->compress_init();
|
---|
3600 | sccomp->decompress_init();
|
---|
3601 | /*
|
---|
3602 | * Set IVs after keys. Here we use the exchange hash from the
|
---|
3603 | * _first_ key exchange.
|
---|
3604 | */
|
---|
3605 | if (first_kex)
|
---|
3606 | memcpy(ssh2_session_id, exchange_hash, sizeof(exchange_hash));
|
---|
3607 | ssh2_mkkey(K, exchange_hash, ssh2_session_id, 'C', keyspace);
|
---|
3608 | cscipher->setcskey(keyspace);
|
---|
3609 | ssh2_mkkey(K, exchange_hash, ssh2_session_id, 'D', keyspace);
|
---|
3610 | sccipher->setsckey(keyspace);
|
---|
3611 | ssh2_mkkey(K, exchange_hash, ssh2_session_id, 'A', keyspace);
|
---|
3612 | cscipher->setcsiv(keyspace);
|
---|
3613 | ssh2_mkkey(K, exchange_hash, ssh2_session_id, 'B', keyspace);
|
---|
3614 | sccipher->setsciv(keyspace);
|
---|
3615 | ssh2_mkkey(K, exchange_hash, ssh2_session_id, 'E', keyspace);
|
---|
3616 | csmac->setcskey(keyspace);
|
---|
3617 | ssh2_mkkey(K, exchange_hash, ssh2_session_id, 'F', keyspace);
|
---|
3618 | scmac->setsckey(keyspace);
|
---|
3619 |
|
---|
3620 | /*
|
---|
3621 | * If this is the first key exchange phase, we must pass the
|
---|
3622 | * SSH2_MSG_NEWKEYS packet to the next layer, not because it
|
---|
3623 | * wants to see it but because it will need time to initialise
|
---|
3624 | * itself before it sees an actual packet. In subsequent key
|
---|
3625 | * exchange phases, we don't pass SSH2_MSG_NEWKEYS on, because
|
---|
3626 | * it would only confuse the layer above.
|
---|
3627 | */
|
---|
3628 | if (!first_kex) {
|
---|
3629 | crReturn(0);
|
---|
3630 | }
|
---|
3631 | first_kex = 0;
|
---|
3632 |
|
---|
3633 | /*
|
---|
3634 | * Now we're encrypting. Begin returning 1 to the protocol main
|
---|
3635 | * function so that other things can run on top of the
|
---|
3636 | * transport. If we ever see a KEXINIT, we must go back to the
|
---|
3637 | * start.
|
---|
3638 | */
|
---|
3639 | while (!(ispkt && pktin.type == SSH2_MSG_KEXINIT)) {
|
---|
3640 | crReturn(1);
|
---|
3641 | }
|
---|
3642 | logevent("Server initiated key re-exchange");
|
---|
3643 | goto begin_key_exchange;
|
---|
3644 |
|
---|
3645 | crFinish(1);
|
---|
3646 | }
|
---|
3647 |
|
---|
3648 | /*
|
---|
3649 | * Add data to an SSH2 channel output buffer.
|
---|
3650 | */
|
---|
3651 | static void ssh2_add_channel_data(struct ssh_channel *c, char *buf,
|
---|
3652 | int len)
|
---|
3653 | {
|
---|
3654 | bufchain_add(&c->v.v2.outbuffer, buf, len);
|
---|
3655 | }
|
---|
3656 |
|
---|
3657 | /*
|
---|
3658 | * Attempt to send data on an SSH2 channel.
|
---|
3659 | */
|
---|
3660 | static int ssh2_try_send(struct ssh_channel *c)
|
---|
3661 | {
|
---|
3662 | while (c->v.v2.remwindow > 0 && bufchain_size(&c->v.v2.outbuffer) > 0) {
|
---|
3663 | int len;
|
---|
3664 | void *data;
|
---|
3665 | bufchain_prefix(&c->v.v2.outbuffer, &data, &len);
|
---|
3666 | if ((unsigned)len > c->v.v2.remwindow)
|
---|
3667 | len = c->v.v2.remwindow;
|
---|
3668 | if ((unsigned)len > c->v.v2.remmaxpkt)
|
---|
3669 | len = c->v.v2.remmaxpkt;
|
---|
3670 | ssh2_pkt_init(SSH2_MSG_CHANNEL_DATA);
|
---|
3671 | ssh2_pkt_adduint32(c->remoteid);
|
---|
3672 | ssh2_pkt_addstring_start();
|
---|
3673 | ssh2_pkt_addstring_data(data, len);
|
---|
3674 | ssh2_pkt_send();
|
---|
3675 | bufchain_consume(&c->v.v2.outbuffer, len);
|
---|
3676 | c->v.v2.remwindow -= len;
|
---|
3677 | }
|
---|
3678 |
|
---|
3679 | /*
|
---|
3680 | * After having sent as much data as we can, return the amount
|
---|
3681 | * still buffered.
|
---|
3682 | */
|
---|
3683 | return bufchain_size(&c->v.v2.outbuffer);
|
---|
3684 | }
|
---|
3685 |
|
---|
3686 | /*
|
---|
3687 | * Potentially enlarge the window on an SSH2 channel.
|
---|
3688 | */
|
---|
3689 | static void ssh2_set_window(struct ssh_channel *c, unsigned newwin)
|
---|
3690 | {
|
---|
3691 | /*
|
---|
3692 | * Never send WINDOW_ADJUST for a channel that the remote side
|
---|
3693 | * already thinks it's closed; there's no point, since it won't
|
---|
3694 | * be sending any more data anyway.
|
---|
3695 | */
|
---|
3696 | if (c->closes != 0)
|
---|
3697 | return;
|
---|
3698 |
|
---|
3699 | if (newwin > c->v.v2.locwindow) {
|
---|
3700 | ssh2_pkt_init(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
|
---|
3701 | ssh2_pkt_adduint32(c->remoteid);
|
---|
3702 | ssh2_pkt_adduint32(newwin - c->v.v2.locwindow);
|
---|
3703 | ssh2_pkt_send();
|
---|
3704 | c->v.v2.locwindow = newwin;
|
---|
3705 | }
|
---|
3706 | }
|
---|
3707 |
|
---|
3708 | /*
|
---|
3709 | * Handle the SSH2 userauth and connection layers.
|
---|
3710 | */
|
---|
3711 | static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
|
---|
3712 | {
|
---|
3713 | static enum {
|
---|
3714 | AUTH_INVALID, AUTH_PUBLICKEY_AGENT, AUTH_PUBLICKEY_FILE,
|
---|
3715 | AUTH_PASSWORD,
|
---|
3716 | AUTH_KEYBOARD_INTERACTIVE
|
---|
3717 | } method;
|
---|
3718 | static enum {
|
---|
3719 | AUTH_TYPE_NONE,
|
---|
3720 | AUTH_TYPE_PUBLICKEY,
|
---|
3721 | AUTH_TYPE_PUBLICKEY_OFFER_LOUD,
|
---|
3722 | AUTH_TYPE_PUBLICKEY_OFFER_QUIET,
|
---|
3723 | AUTH_TYPE_PASSWORD,
|
---|
3724 | AUTH_TYPE_KEYBOARD_INTERACTIVE,
|
---|
3725 | AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET
|
---|
3726 | } type;
|
---|
3727 | static int gotit, need_pw, can_pubkey, can_passwd;
|
---|
3728 | static int tried_pubkey_config, tried_agent;
|
---|
3729 | static int we_are_in;
|
---|
3730 | static int num_prompts, curr_prompt, echo;
|
---|
3731 | static char username[100];
|
---|
3732 | static int got_username;
|
---|
3733 | static char pwprompt[200];
|
---|
3734 | static char password[100];
|
---|
3735 | static void *publickey_blob;
|
---|
3736 | static int publickey_bloblen;
|
---|
3737 |
|
---|
3738 | crBegin;
|
---|
3739 |
|
---|
3740 | /*
|
---|
3741 | * Request userauth protocol, and await a response to it.
|
---|
3742 | */
|
---|
3743 | ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST);
|
---|
3744 | ssh2_pkt_addstring("ssh-userauth");
|
---|
3745 | ssh2_pkt_send();
|
---|
3746 | crWaitUntilV(ispkt);
|
---|
3747 | if (pktin.type != SSH2_MSG_SERVICE_ACCEPT) {
|
---|
3748 | bombout(("Server refused user authentication protocol"));
|
---|
3749 | crReturnV;
|
---|
3750 | }
|
---|
3751 |
|
---|
3752 | /*
|
---|
3753 | * We repeat this whole loop, including the username prompt,
|
---|
3754 | * until we manage a successful authentication. If the user
|
---|
3755 | * types the wrong _password_, they are sent back to the
|
---|
3756 | * beginning to try another username. (If they specify a
|
---|
3757 | * username in the config, they are never asked, even if they
|
---|
3758 | * do give a wrong password.)
|
---|
3759 | *
|
---|
3760 | * I think this best serves the needs of
|
---|
3761 | *
|
---|
3762 | * - the people who have no configuration, no keys, and just
|
---|
3763 | * want to try repeated (username,password) pairs until they
|
---|
3764 | * type both correctly
|
---|
3765 | *
|
---|
3766 | * - people who have keys and configuration but occasionally
|
---|
3767 | * need to fall back to passwords
|
---|
3768 | *
|
---|
3769 | * - people with a key held in Pageant, who might not have
|
---|
3770 | * logged in to a particular machine before; so they want to
|
---|
3771 | * type a username, and then _either_ their key will be
|
---|
3772 | * accepted, _or_ they will type a password. If they mistype
|
---|
3773 | * the username they will want to be able to get back and
|
---|
3774 | * retype it!
|
---|
3775 | */
|
---|
3776 | username[0] = '\0';
|
---|
3777 | got_username = FALSE;
|
---|
3778 | do {
|
---|
3779 | static char c;
|
---|
3780 |
|
---|
3781 | /*
|
---|
3782 | * Get a username.
|
---|
3783 | */
|
---|
3784 | if (got_username && !cfg.change_username) {
|
---|
3785 | /*
|
---|
3786 | * We got a username last time round this loop, and
|
---|
3787 | * with change_username turned off we don't try to get
|
---|
3788 | * it again.
|
---|
3789 | */
|
---|
3790 | } else if ((flags & FLAG_INTERACTIVE) && !*cfg.username) {
|
---|
3791 | logevent("No username provided. Abandoning session.");
|
---|
3792 | } else {
|
---|
3793 | strncpy(username, cfg.username, 99);
|
---|
3794 | username[99] = '\0';
|
---|
3795 | FzSFtpIpc_Trace1("Using username \"%s\"", username);
|
---|
3796 | }
|
---|
3797 | got_username = TRUE;
|
---|
3798 |
|
---|
3799 | /*
|
---|
3800 | * Send an authentication request using method "none": (a)
|
---|
3801 | * just in case it succeeds, and (b) so that we know what
|
---|
3802 | * authentication methods we can usefully try next.
|
---|
3803 | */
|
---|
3804 | ssh_pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
|
---|
3805 |
|
---|
3806 | ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
|
---|
3807 | ssh2_pkt_addstring(username);
|
---|
3808 | ssh2_pkt_addstring("ssh-connection"); /* service requested */
|
---|
3809 | ssh2_pkt_addstring("none"); /* method */
|
---|
3810 | ssh2_pkt_send();
|
---|
3811 | type = AUTH_TYPE_NONE;
|
---|
3812 | gotit = FALSE;
|
---|
3813 | we_are_in = FALSE;
|
---|
3814 |
|
---|
3815 | tried_pubkey_config = FALSE;
|
---|
3816 | tried_agent = FALSE;
|
---|
3817 | /* Load the pub half of cfg.keyfile so we notice if it's in Pageant */
|
---|
3818 | if (*cfg.keyfile) {
|
---|
3819 | int keytype;
|
---|
3820 | logeventf("Reading private key file \"%.150s\"", cfg.keyfile);
|
---|
3821 | keytype = key_type(cfg.keyfile);
|
---|
3822 | if (keytype == SSH_KEYTYPE_SSH2)
|
---|
3823 | publickey_blob = ssh2_userkey_loadpub(cfg.keyfile, NULL,
|
---|
3824 | &publickey_bloblen);
|
---|
3825 | else {
|
---|
3826 | char msgbuf[256];
|
---|
3827 | logeventf("Unable to use this key file (%s)",
|
---|
3828 | key_type_to_str(keytype));
|
---|
3829 | sprintf(msgbuf, "Unable to use key file \"%.150s\" (%s)\r\n",
|
---|
3830 | cfg.keyfile, key_type_to_str(keytype));
|
---|
3831 | c_write_str(msgbuf);
|
---|
3832 | publickey_blob = NULL;
|
---|
3833 | }
|
---|
3834 | } else
|
---|
3835 | publickey_blob = NULL;
|
---|
3836 |
|
---|
3837 | while (1) {
|
---|
3838 | /*
|
---|
3839 | * Wait for the result of the last authentication request.
|
---|
3840 | */
|
---|
3841 | if (!gotit)
|
---|
3842 | crWaitUntilV(ispkt);
|
---|
3843 | while (pktin.type == SSH2_MSG_USERAUTH_BANNER) {
|
---|
3844 | char *banner;
|
---|
3845 | int size;
|
---|
3846 | /*
|
---|
3847 | * Don't show the banner if we're operating in
|
---|
3848 | * non-verbose non-interactive mode. (It's probably
|
---|
3849 | * a script, which means nobody will read the
|
---|
3850 | * banner _anyway_, and moreover the printing of
|
---|
3851 | * the banner will screw up processing on the
|
---|
3852 | * output of (say) plink.)
|
---|
3853 | */
|
---|
3854 | if (flags & (FLAG_VERBOSE | FLAG_INTERACTIVE)) {
|
---|
3855 | ssh2_pkt_getstring(&banner, &size);
|
---|
3856 | if (banner)
|
---|
3857 | c_write_untrusted(banner, size);
|
---|
3858 | }
|
---|
3859 | crWaitUntilV(ispkt);
|
---|
3860 | }
|
---|
3861 | if (pktin.type == SSH2_MSG_USERAUTH_SUCCESS) {
|
---|
3862 | logevent("Access granted");
|
---|
3863 | we_are_in = TRUE;
|
---|
3864 | break;
|
---|
3865 | }
|
---|
3866 |
|
---|
3867 | if (pktin.type != SSH2_MSG_USERAUTH_FAILURE) {
|
---|
3868 | bombout(("Strange packet received during authentication: type %d",
|
---|
3869 | pktin.type));
|
---|
3870 | crReturnV;
|
---|
3871 | }
|
---|
3872 |
|
---|
3873 | gotit = FALSE;
|
---|
3874 |
|
---|
3875 | /*
|
---|
3876 | * OK, we're now sitting on a USERAUTH_FAILURE message, so
|
---|
3877 | * we can look at the string in it and know what we can
|
---|
3878 | * helpfully try next.
|
---|
3879 | */
|
---|
3880 | if (pktin.type == SSH2_MSG_USERAUTH_FAILURE) {
|
---|
3881 | char *methods;
|
---|
3882 | int methlen;
|
---|
3883 | ssh2_pkt_getstring(&methods, &methlen);
|
---|
3884 | if (!ssh2_pkt_getbool()) {
|
---|
3885 | /*
|
---|
3886 | * We have received an unequivocal Access
|
---|
3887 | * Denied. This can translate to a variety of
|
---|
3888 | * messages:
|
---|
3889 | *
|
---|
3890 | * - if we'd just tried "none" authentication,
|
---|
3891 | * it's not worth printing anything at all
|
---|
3892 | *
|
---|
3893 | * - if we'd just tried a public key _offer_,
|
---|
3894 | * the message should be "Server refused our
|
---|
3895 | * key" (or no message at all if the key
|
---|
3896 | * came from Pageant)
|
---|
3897 | *
|
---|
3898 | * - if we'd just tried anything else, the
|
---|
3899 | * message really should be "Access denied".
|
---|
3900 | *
|
---|
3901 | * Additionally, if we'd just tried password
|
---|
3902 | * authentication, we should break out of this
|
---|
3903 | * whole loop so as to go back to the username
|
---|
3904 | * prompt.
|
---|
3905 | */
|
---|
3906 | if (type == AUTH_TYPE_NONE) {
|
---|
3907 | /* do nothing */
|
---|
3908 | } else if (type == AUTH_TYPE_PUBLICKEY_OFFER_LOUD ||
|
---|
3909 | type == AUTH_TYPE_PUBLICKEY_OFFER_QUIET) {
|
---|
3910 | logevent("Server refused public key");
|
---|
3911 | //} else if (type == AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET) {
|
---|
3912 | /* server declined keyboard-interactive; ignore */
|
---|
3913 | } else {
|
---|
3914 | logevent("Access denied");
|
---|
3915 | if (type == AUTH_TYPE_PASSWORD) {
|
---|
3916 | we_are_in = FALSE;
|
---|
3917 | break;
|
---|
3918 | }
|
---|
3919 | }
|
---|
3920 | } else {
|
---|
3921 | logevent("Further authentication required");
|
---|
3922 | }
|
---|
3923 |
|
---|
3924 | can_pubkey =
|
---|
3925 | in_commasep_string("publickey", methods, methlen);
|
---|
3926 | can_passwd =
|
---|
3927 | in_commasep_string("password", methods, methlen);
|
---|
3928 | }
|
---|
3929 |
|
---|
3930 | method = 0;
|
---|
3931 | ssh_pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
|
---|
3932 |
|
---|
3933 | /*
|
---|
3934 | * Most password/passphrase prompts will be
|
---|
3935 | * non-echoing, so we set this to 0 by default.
|
---|
3936 | * Exception is that some keyboard-interactive prompts
|
---|
3937 | * can be echoing, in which case we'll set this to 1.
|
---|
3938 | */
|
---|
3939 | echo = 0;
|
---|
3940 |
|
---|
3941 | if (!method && can_pubkey && agent_exists() && !tried_agent) {
|
---|
3942 | /*
|
---|
3943 | * Attempt public-key authentication using Pageant.
|
---|
3944 | */
|
---|
3945 | static unsigned char request[5], *response, *p;
|
---|
3946 | static int responselen;
|
---|
3947 | static int i, nkeys;
|
---|
3948 | static int authed = FALSE;
|
---|
3949 | void *r;
|
---|
3950 |
|
---|
3951 | ssh_pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
|
---|
3952 | ssh_pkt_ctx |= SSH2_PKTCTX_PUBLICKEY;
|
---|
3953 |
|
---|
3954 | tried_agent = TRUE;
|
---|
3955 |
|
---|
3956 | logevent("Pageant is running. Requesting keys.");
|
---|
3957 |
|
---|
3958 | /* Request the keys held by the agent. */
|
---|
3959 | PUT_32BIT(request, 1);
|
---|
3960 | request[4] = SSH2_AGENTC_REQUEST_IDENTITIES;
|
---|
3961 | agent_query(request, 5, &r, &responselen);
|
---|
3962 | response = (unsigned char *) r;
|
---|
3963 | if (response && responselen >= 5 &&
|
---|
3964 | response[4] == SSH2_AGENT_IDENTITIES_ANSWER) {
|
---|
3965 | p = response + 5;
|
---|
3966 | nkeys = GET_32BIT(p);
|
---|
3967 | p += 4;
|
---|
3968 | {
|
---|
3969 | char buf[64];
|
---|
3970 | sprintf(buf, "Pageant has %d SSH2 keys", nkeys);
|
---|
3971 | logevent(buf);
|
---|
3972 | }
|
---|
3973 | for (i = 0; i < nkeys; i++) {
|
---|
3974 | static char *pkblob, *alg, *commentp;
|
---|
3975 | static int pklen, alglen, commentlen;
|
---|
3976 | static int siglen, retlen, len;
|
---|
3977 | static char *q, *agentreq, *ret;
|
---|
3978 | void *vret;
|
---|
3979 |
|
---|
3980 | {
|
---|
3981 | char buf[64];
|
---|
3982 | sprintf(buf, "Trying Pageant key #%d", i);
|
---|
3983 | logevent(buf);
|
---|
3984 | }
|
---|
3985 | pklen = GET_32BIT(p);
|
---|
3986 | p += 4;
|
---|
3987 | if (publickey_blob &&
|
---|
3988 | pklen == publickey_bloblen &&
|
---|
3989 | !memcmp(p, publickey_blob, publickey_bloblen)) {
|
---|
3990 | logevent("This key matches configured key file");
|
---|
3991 | tried_pubkey_config = 1;
|
---|
3992 | }
|
---|
3993 | pkblob = p;
|
---|
3994 | p += pklen;
|
---|
3995 | alglen = GET_32BIT(pkblob);
|
---|
3996 | alg = pkblob + 4;
|
---|
3997 | commentlen = GET_32BIT(p);
|
---|
3998 | p += 4;
|
---|
3999 | commentp = p;
|
---|
4000 | p += commentlen;
|
---|
4001 | ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
|
---|
4002 | ssh2_pkt_addstring(username);
|
---|
4003 | ssh2_pkt_addstring("ssh-connection"); /* service requested */
|
---|
4004 | ssh2_pkt_addstring("publickey"); /* method */
|
---|
4005 | ssh2_pkt_addbool(FALSE); /* no signature included */
|
---|
4006 | ssh2_pkt_addstring_start();
|
---|
4007 | ssh2_pkt_addstring_data(alg, alglen);
|
---|
4008 | ssh2_pkt_addstring_start();
|
---|
4009 | ssh2_pkt_addstring_data(pkblob, pklen);
|
---|
4010 | ssh2_pkt_send();
|
---|
4011 |
|
---|
4012 | crWaitUntilV(ispkt);
|
---|
4013 | if (pktin.type != SSH2_MSG_USERAUTH_PK_OK) {
|
---|
4014 | logevent("Key refused");
|
---|
4015 | continue;
|
---|
4016 | }
|
---|
4017 |
|
---|
4018 | /*
|
---|
4019 | * Server is willing to accept the key.
|
---|
4020 | * Construct a SIGN_REQUEST.
|
---|
4021 | */
|
---|
4022 | ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
|
---|
4023 | ssh2_pkt_addstring(username);
|
---|
4024 | ssh2_pkt_addstring("ssh-connection"); /* service requested */
|
---|
4025 | ssh2_pkt_addstring("publickey"); /* method */
|
---|
4026 | ssh2_pkt_addbool(TRUE);
|
---|
4027 | ssh2_pkt_addstring_start();
|
---|
4028 | ssh2_pkt_addstring_data(alg, alglen);
|
---|
4029 | ssh2_pkt_addstring_start();
|
---|
4030 | ssh2_pkt_addstring_data(pkblob, pklen);
|
---|
4031 |
|
---|
4032 | siglen = pktout.length - 5 + 4 + 20;
|
---|
4033 | len = 1; /* message type */
|
---|
4034 | len += 4 + pklen; /* key blob */
|
---|
4035 | len += 4 + siglen; /* data to sign */
|
---|
4036 | len += 4; /* flags */
|
---|
4037 | agentreq = smalloc(4 + len);
|
---|
4038 | PUT_32BIT(agentreq, len);
|
---|
4039 | q = agentreq + 4;
|
---|
4040 | *q++ = SSH2_AGENTC_SIGN_REQUEST;
|
---|
4041 | PUT_32BIT(q, pklen);
|
---|
4042 | q += 4;
|
---|
4043 | memcpy(q, pkblob, pklen);
|
---|
4044 | q += pklen;
|
---|
4045 | PUT_32BIT(q, siglen);
|
---|
4046 | q += 4;
|
---|
4047 | /* Now the data to be signed... */
|
---|
4048 | PUT_32BIT(q, 20);
|
---|
4049 | q += 4;
|
---|
4050 | memcpy(q, ssh2_session_id, 20);
|
---|
4051 | q += 20;
|
---|
4052 | memcpy(q, pktout.data + 5, pktout.length - 5);
|
---|
4053 | q += pktout.length - 5;
|
---|
4054 | /* And finally the (zero) flags word. */
|
---|
4055 | PUT_32BIT(q, 0);
|
---|
4056 | agent_query(agentreq, len + 4, &vret, &retlen);
|
---|
4057 | ret = vret;
|
---|
4058 | sfree(agentreq);
|
---|
4059 | if (ret) {
|
---|
4060 | if (ret[4] == SSH2_AGENT_SIGN_RESPONSE) {
|
---|
4061 | logevent("Sending Pageant's response");
|
---|
4062 | ssh2_add_sigblob(pkblob, pklen,
|
---|
4063 | ret + 9, GET_32BIT(ret + 5));
|
---|
4064 | ssh2_pkt_send();
|
---|
4065 | authed = TRUE;
|
---|
4066 | break;
|
---|
4067 | } else {
|
---|
4068 | logevent
|
---|
4069 | ("Pageant failed to answer challenge");
|
---|
4070 | sfree(ret);
|
---|
4071 | }
|
---|
4072 | }
|
---|
4073 | }
|
---|
4074 | if (authed)
|
---|
4075 | continue;
|
---|
4076 | }
|
---|
4077 | }
|
---|
4078 |
|
---|
4079 | if (!method && can_pubkey && publickey_blob
|
---|
4080 | && !tried_pubkey_config)
|
---|
4081 | {
|
---|
4082 | unsigned char *pub_blob;
|
---|
4083 | char *algorithm, *comment;
|
---|
4084 | int pub_blob_len;
|
---|
4085 |
|
---|
4086 | tried_pubkey_config = TRUE;
|
---|
4087 |
|
---|
4088 | ssh_pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
|
---|
4089 | ssh_pkt_ctx |= SSH2_PKTCTX_PUBLICKEY;
|
---|
4090 |
|
---|
4091 | /*
|
---|
4092 | * Try the public key supplied in the configuration.
|
---|
4093 | *
|
---|
4094 | * First, offer the public blob to see if the server is
|
---|
4095 | * willing to accept it.
|
---|
4096 | */
|
---|
4097 | pub_blob = ssh2_userkey_loadpub(cfg.keyfile, &algorithm,
|
---|
4098 | &pub_blob_len);
|
---|
4099 | if (pub_blob)
|
---|
4100 | {
|
---|
4101 | if (!ssh2_userkey_encrypted(cfg.keyfile, &comment))
|
---|
4102 | {
|
---|
4103 | ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
|
---|
4104 | ssh2_pkt_addstring(username);
|
---|
4105 | ssh2_pkt_addstring("ssh-connection"); /* service requested */
|
---|
4106 | ssh2_pkt_addstring("publickey"); /* method */
|
---|
4107 | ssh2_pkt_addbool(FALSE); /* no signature included */
|
---|
4108 | ssh2_pkt_addstring(algorithm);
|
---|
4109 | ssh2_pkt_addstring_start();
|
---|
4110 | ssh2_pkt_addstring_data(pub_blob, pub_blob_len);
|
---|
4111 | ssh2_pkt_send();
|
---|
4112 | logevent("Offered public key from config"); /* FIXME */
|
---|
4113 |
|
---|
4114 | crWaitUntilV(ispkt);
|
---|
4115 | if (pktin.type != SSH2_MSG_USERAUTH_PK_OK)
|
---|
4116 | {
|
---|
4117 | gotit = TRUE;
|
---|
4118 | type = AUTH_TYPE_PUBLICKEY_OFFER_LOUD;
|
---|
4119 | continue; /* key refused; give up on it */
|
---|
4120 | }
|
---|
4121 |
|
---|
4122 | logevent("Offer of public key accepted");
|
---|
4123 | /*
|
---|
4124 | * Actually attempt a serious authentication using
|
---|
4125 | * the key.
|
---|
4126 | */
|
---|
4127 |
|
---|
4128 | if (ssh2_userkey_encrypted(cfg.keyfile, &comment)) {
|
---|
4129 | need_pw = TRUE;
|
---|
4130 | } else {
|
---|
4131 | need_pw = FALSE;
|
---|
4132 | }
|
---|
4133 | method = AUTH_PUBLICKEY_FILE;
|
---|
4134 | }
|
---|
4135 | else
|
---|
4136 | logevent("Ignoring password protected public key");
|
---|
4137 | }
|
---|
4138 | }
|
---|
4139 |
|
---|
4140 | if (!method && can_passwd) {
|
---|
4141 | method = AUTH_PASSWORD;
|
---|
4142 | ssh_pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
|
---|
4143 | ssh_pkt_ctx |= SSH2_PKTCTX_PASSWORD;
|
---|
4144 | sprintf(pwprompt, "%.90s@%.90s's password: ", username,
|
---|
4145 | savedhost);
|
---|
4146 | need_pw = TRUE;
|
---|
4147 | }
|
---|
4148 |
|
---|
4149 | if (need_pw) {
|
---|
4150 | assert (ssh_get_line);
|
---|
4151 | if (!ssh_get_line(pwprompt, password,
|
---|
4152 | sizeof(password), TRUE)) {
|
---|
4153 | /*
|
---|
4154 | * get_line failed to get a password (for
|
---|
4155 | * example because one was supplied on the
|
---|
4156 | * command line which has already failed to
|
---|
4157 | * work). Terminate.
|
---|
4158 | */
|
---|
4159 | ssh2_pkt_init(SSH2_MSG_DISCONNECT);
|
---|
4160 | ssh2_pkt_adduint32(SSH2_DISCONNECT_BY_APPLICATION);
|
---|
4161 | ssh2_pkt_addstring
|
---|
4162 | ("No more passwords available to try");
|
---|
4163 | ssh2_pkt_addstring("en"); /* language tag */
|
---|
4164 | ssh2_pkt_send();
|
---|
4165 | connection_fatal("Unable to authenticate");
|
---|
4166 | ssh_state = SSH_STATE_CLOSED;
|
---|
4167 | crReturnV;
|
---|
4168 | }
|
---|
4169 | }
|
---|
4170 |
|
---|
4171 | if (method == AUTH_PUBLICKEY_FILE) {
|
---|
4172 | /*
|
---|
4173 | * We have our passphrase. Now try the actual authentication.
|
---|
4174 | */
|
---|
4175 | struct ssh2_userkey *key;
|
---|
4176 |
|
---|
4177 | key = ssh2_load_userkey(cfg.keyfile, password);
|
---|
4178 | if (key == SSH2_WRONG_PASSPHRASE || key == NULL) {
|
---|
4179 | if (key == SSH2_WRONG_PASSPHRASE) {
|
---|
4180 | c_write_str("Wrong passphrase\r\n");
|
---|
4181 | tried_pubkey_config = FALSE;
|
---|
4182 | } else {
|
---|
4183 | c_write_str("Unable to load private key\r\n");
|
---|
4184 | tried_pubkey_config = TRUE;
|
---|
4185 | }
|
---|
4186 | /* Send a spurious AUTH_NONE to return to the top. */
|
---|
4187 | ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
|
---|
4188 | ssh2_pkt_addstring(username);
|
---|
4189 | ssh2_pkt_addstring("ssh-connection"); /* service requested */
|
---|
4190 | ssh2_pkt_addstring("none"); /* method */
|
---|
4191 | ssh2_pkt_send();
|
---|
4192 | type = AUTH_TYPE_NONE;
|
---|
4193 | } else {
|
---|
4194 | unsigned char *pkblob, *sigblob, *sigdata;
|
---|
4195 | int pkblob_len, sigblob_len, sigdata_len;
|
---|
4196 |
|
---|
4197 | /*
|
---|
4198 | * We have loaded the private key and the server
|
---|
4199 | * has announced that it's willing to accept it.
|
---|
4200 | * Hallelujah. Generate a signature and send it.
|
---|
4201 | */
|
---|
4202 | ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
|
---|
4203 | ssh2_pkt_addstring(username);
|
---|
4204 | ssh2_pkt_addstring("ssh-connection"); /* service requested */
|
---|
4205 | ssh2_pkt_addstring("publickey"); /* method */
|
---|
4206 | ssh2_pkt_addbool(TRUE);
|
---|
4207 | ssh2_pkt_addstring(key->alg->name);
|
---|
4208 | pkblob = key->alg->public_blob(key->data, &pkblob_len);
|
---|
4209 | ssh2_pkt_addstring_start();
|
---|
4210 | ssh2_pkt_addstring_data(pkblob, pkblob_len);
|
---|
4211 |
|
---|
4212 | /*
|
---|
4213 | * The data to be signed is:
|
---|
4214 | *
|
---|
4215 | * string session-id
|
---|
4216 | *
|
---|
4217 | * followed by everything so far placed in the
|
---|
4218 | * outgoing packet.
|
---|
4219 | */
|
---|
4220 | sigdata_len = pktout.length - 5 + 4 + 20;
|
---|
4221 | sigdata = smalloc(sigdata_len);
|
---|
4222 | PUT_32BIT(sigdata, 20);
|
---|
4223 | memcpy(sigdata + 4, ssh2_session_id, 20);
|
---|
4224 | memcpy(sigdata + 24, pktout.data + 5,
|
---|
4225 | pktout.length - 5);
|
---|
4226 | sigblob = key->alg->sign(key->data, sigdata,
|
---|
4227 | sigdata_len, &sigblob_len);
|
---|
4228 | ssh2_add_sigblob(pkblob, pkblob_len,
|
---|
4229 | sigblob, sigblob_len);
|
---|
4230 | sfree(pkblob);
|
---|
4231 | sfree(sigblob);
|
---|
4232 | sfree(sigdata);
|
---|
4233 |
|
---|
4234 | ssh2_pkt_send();
|
---|
4235 | type = AUTH_TYPE_PUBLICKEY;
|
---|
4236 | }
|
---|
4237 | } else if (method == AUTH_PASSWORD) {
|
---|
4238 | /*
|
---|
4239 | * We send the password packet lumped tightly together with
|
---|
4240 | * an SSH_MSG_IGNORE packet. The IGNORE packet contains a
|
---|
4241 | * string long enough to make the total length of the two
|
---|
4242 | * packets constant. This should ensure that a passive
|
---|
4243 | * listener doing traffic analyis can't work out the length
|
---|
4244 | * of the password.
|
---|
4245 | *
|
---|
4246 | * For this to work, we need an assumption about the
|
---|
4247 | * maximum length of the password packet. I think 256 is
|
---|
4248 | * pretty conservative. Anyone using a password longer than
|
---|
4249 | * that probably doesn't have much to worry about from
|
---|
4250 | * people who find out how long their password is!
|
---|
4251 | */
|
---|
4252 | ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
|
---|
4253 | ssh2_pkt_addstring(username);
|
---|
4254 | ssh2_pkt_addstring("ssh-connection"); /* service requested */
|
---|
4255 | ssh2_pkt_addstring("password");
|
---|
4256 | ssh2_pkt_addbool(FALSE);
|
---|
4257 | ssh2_pkt_addstring(password);
|
---|
4258 | ssh2_pkt_defer();
|
---|
4259 | /*
|
---|
4260 | * We'll include a string that's an exact multiple of the
|
---|
4261 | * cipher block size. If the cipher is NULL for some
|
---|
4262 | * reason, we don't do this trick at all because we gain
|
---|
4263 | * nothing by it.
|
---|
4264 | */
|
---|
4265 | if (cscipher) {
|
---|
4266 | int stringlen, i;
|
---|
4267 |
|
---|
4268 | stringlen = (256 - deferred_len);
|
---|
4269 | stringlen += cscipher->blksize - 1;
|
---|
4270 | stringlen -= (stringlen % cscipher->blksize);
|
---|
4271 | if (cscomp) {
|
---|
4272 | /*
|
---|
4273 | * Temporarily disable actual compression,
|
---|
4274 | * so we can guarantee to get this string
|
---|
4275 | * exactly the length we want it. The
|
---|
4276 | * compression-disabling routine should
|
---|
4277 | * return an integer indicating how many
|
---|
4278 | * bytes we should adjust our string length
|
---|
4279 | * by.
|
---|
4280 | */
|
---|
4281 | stringlen -= cscomp->disable_compression();
|
---|
4282 | }
|
---|
4283 | ssh2_pkt_init(SSH2_MSG_IGNORE);
|
---|
4284 | ssh2_pkt_addstring_start();
|
---|
4285 | for (i = 0; i < stringlen; i++) {
|
---|
4286 | char c = (char) random_byte();
|
---|
4287 | ssh2_pkt_addstring_data(&c, 1);
|
---|
4288 | }
|
---|
4289 | ssh2_pkt_defer();
|
---|
4290 | }
|
---|
4291 | ssh_pkt_defersend();
|
---|
4292 | logevent("Sent password");
|
---|
4293 | type = AUTH_TYPE_PASSWORD;
|
---|
4294 | /* } else if (method == AUTH_KEYBOARD_INTERACTIVE) {
|
---|
4295 | if (curr_prompt == 0) {
|
---|
4296 | ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE);
|
---|
4297 | ssh2_pkt_adduint32(num_prompts);
|
---|
4298 | }
|
---|
4299 | if (need_pw) { /* only add pw if we just got one! */
|
---|
4300 | /* ssh2_pkt_addstring(password);
|
---|
4301 | memset(password, 0, sizeof(password));
|
---|
4302 | curr_prompt++;
|
---|
4303 | }
|
---|
4304 | if (curr_prompt >= num_prompts) {
|
---|
4305 | ssh2_pkt_send();
|
---|
4306 | }
|
---|
4307 | else {
|
---|
4308 | /* If there are prompts remaining, we set
|
---|
4309 | * `gotit´ so that we won't attempt to get
|
---|
4310 | * another packet. Then we go back round the
|
---|
4311 | * loop and will end up retrieving another
|
---|
4312 | * prompt out of the existing packet. Funky or
|
---|
4313 | * what?
|
---|
4314 | */
|
---|
4315 | /* gotit = TRUE;
|
---|
4316 | }
|
---|
4317 | type = AUTH_TYPE_KEYBOARD_INTERACTIVE;*/
|
---|
4318 | } else {
|
---|
4319 | c_write_str
|
---|
4320 | ("No supported authentication methods left to try!\r\n");
|
---|
4321 | logevent
|
---|
4322 | ("No supported authentications offered. Disconnecting");
|
---|
4323 | ssh2_pkt_init(SSH2_MSG_DISCONNECT);
|
---|
4324 | ssh2_pkt_adduint32(SSH2_DISCONNECT_BY_APPLICATION);
|
---|
4325 | ssh2_pkt_addstring
|
---|
4326 | ("No supported authentication methods available");
|
---|
4327 | ssh2_pkt_addstring("en"); /* language tag */
|
---|
4328 | ssh2_pkt_send();
|
---|
4329 | ssh_state = SSH_STATE_CLOSED;
|
---|
4330 | crReturnV;
|
---|
4331 | }
|
---|
4332 | }
|
---|
4333 | } while (!we_are_in);
|
---|
4334 |
|
---|
4335 | /*
|
---|
4336 | * Now we're authenticated for the connection protocol. The
|
---|
4337 | * connection protocol will automatically have started at this
|
---|
4338 | * point; there's no need to send SERVICE_REQUEST.
|
---|
4339 | */
|
---|
4340 |
|
---|
4341 | /*
|
---|
4342 | * So now create a channel with a session in it.
|
---|
4343 | */
|
---|
4344 | ssh_channels = newtree234(ssh_channelcmp);
|
---|
4345 | mainchan = smalloc(sizeof(struct ssh_channel));
|
---|
4346 | mainchan->localid = alloc_channel_id();
|
---|
4347 | ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);
|
---|
4348 | ssh2_pkt_addstring("session");
|
---|
4349 | ssh2_pkt_adduint32(mainchan->localid);
|
---|
4350 | mainchan->v.v2.locwindow = OUR_V2_WINSIZE;
|
---|
4351 | ssh2_pkt_adduint32(mainchan->v.v2.locwindow); /* our window size */
|
---|
4352 | ssh2_pkt_adduint32(0x4000UL); /* our max pkt size */
|
---|
4353 | ssh2_pkt_send();
|
---|
4354 | crWaitUntilV(ispkt);
|
---|
4355 | if (pktin.type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {
|
---|
4356 | bombout(("Server refused to open a session"));
|
---|
4357 | crReturnV;
|
---|
4358 | /* FIXME: error data comes back in FAILURE packet */
|
---|
4359 | }
|
---|
4360 | if (ssh2_pkt_getuint32() != mainchan->localid) {
|
---|
4361 | bombout(("Server's channel confirmation cited wrong channel"));
|
---|
4362 | crReturnV;
|
---|
4363 | }
|
---|
4364 | mainchan->remoteid = ssh2_pkt_getuint32();
|
---|
4365 | mainchan->type = CHAN_MAINSESSION;
|
---|
4366 | mainchan->closes = 0;
|
---|
4367 | mainchan->v.v2.remwindow = ssh2_pkt_getuint32();
|
---|
4368 | mainchan->v.v2.remmaxpkt = ssh2_pkt_getuint32();
|
---|
4369 | bufchain_init(&mainchan->v.v2.outbuffer);
|
---|
4370 | add234(ssh_channels, mainchan);
|
---|
4371 | logevent("Opened channel for session");
|
---|
4372 |
|
---|
4373 | /*
|
---|
4374 | * Now allocate a pty for the session.
|
---|
4375 | */
|
---|
4376 | if (!cfg.nopty) {
|
---|
4377 | ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
|
---|
4378 | ssh2_pkt_adduint32(mainchan->remoteid); /* recipient channel */
|
---|
4379 | ssh2_pkt_addstring("pty-req");
|
---|
4380 | ssh2_pkt_addbool(1); /* want reply */
|
---|
4381 | ssh2_pkt_addstring(cfg.termtype);
|
---|
4382 | ssh2_pkt_adduint32(cols);
|
---|
4383 | ssh2_pkt_adduint32(rows);
|
---|
4384 | ssh2_pkt_adduint32(0); /* pixel width */
|
---|
4385 | ssh2_pkt_adduint32(0); /* pixel height */
|
---|
4386 | ssh2_pkt_addstring_start();
|
---|
4387 | ssh2_pkt_addstring_data("\0", 1); /* TTY_OP_END, no special options */
|
---|
4388 | ssh2_pkt_send();
|
---|
4389 | ssh_state = SSH_STATE_INTERMED;
|
---|
4390 |
|
---|
4391 | do {
|
---|
4392 | crWaitUntilV(ispkt);
|
---|
4393 | if (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {
|
---|
4394 | unsigned i = ssh2_pkt_getuint32();
|
---|
4395 | struct ssh_channel *c;
|
---|
4396 | c = find234(ssh_channels, &i, ssh_channelfind);
|
---|
4397 | if (!c)
|
---|
4398 | continue; /* nonexistent channel */
|
---|
4399 | c->v.v2.remwindow += ssh2_pkt_getuint32();
|
---|
4400 | }
|
---|
4401 | } while (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);
|
---|
4402 |
|
---|
4403 | if (pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {
|
---|
4404 | if (pktin.type != SSH2_MSG_CHANNEL_FAILURE) {
|
---|
4405 | bombout(("Unexpected response to pty request:"
|
---|
4406 | " packet type %d", pktin.type));
|
---|
4407 | crReturnV;
|
---|
4408 | }
|
---|
4409 | c_write_str("Server refused to allocate pty\r\n");
|
---|
4410 | ssh_editing = ssh_echoing = 1;
|
---|
4411 | } else {
|
---|
4412 | logevent("Allocated pty");
|
---|
4413 | }
|
---|
4414 | } else {
|
---|
4415 | ssh_editing = ssh_echoing = 1;
|
---|
4416 | }
|
---|
4417 |
|
---|
4418 | /*
|
---|
4419 | * Start a shell or a remote command. We may have to attempt
|
---|
4420 | * this twice if the config data has provided a second choice
|
---|
4421 | * of command.
|
---|
4422 | */
|
---|
4423 | while (1) {
|
---|
4424 | int subsys;
|
---|
4425 | char *cmd;
|
---|
4426 |
|
---|
4427 | if (ssh_fallback_cmd) {
|
---|
4428 | subsys = cfg.ssh_subsys2;
|
---|
4429 | cmd = cfg.remote_cmd_ptr2;
|
---|
4430 | } else {
|
---|
4431 | subsys = cfg.ssh_subsys;
|
---|
4432 | cmd = cfg.remote_cmd_ptr;
|
---|
4433 | }
|
---|
4434 |
|
---|
4435 | ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
|
---|
4436 | ssh2_pkt_adduint32(mainchan->remoteid); /* recipient channel */
|
---|
4437 | if (subsys) {
|
---|
4438 | ssh2_pkt_addstring("subsystem");
|
---|
4439 | ssh2_pkt_addbool(1); /* want reply */
|
---|
4440 | ssh2_pkt_addstring(cmd);
|
---|
4441 | } else if (*cmd) {
|
---|
4442 | ssh2_pkt_addstring("exec");
|
---|
4443 | ssh2_pkt_addbool(1); /* want reply */
|
---|
4444 | ssh2_pkt_addstring(cmd);
|
---|
4445 | } else {
|
---|
4446 | ssh2_pkt_addstring("shell");
|
---|
4447 | ssh2_pkt_addbool(1); /* want reply */
|
---|
4448 | }
|
---|
4449 | ssh2_pkt_send();
|
---|
4450 | do {
|
---|
4451 | crWaitUntilV(ispkt);
|
---|
4452 | if (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {
|
---|
4453 | unsigned i = ssh2_pkt_getuint32();
|
---|
4454 | struct ssh_channel *c;
|
---|
4455 | c = find234(ssh_channels, &i, ssh_channelfind);
|
---|
4456 | if (!c)
|
---|
4457 | continue; /* nonexistent channel */
|
---|
4458 | c->v.v2.remwindow += ssh2_pkt_getuint32();
|
---|
4459 | }
|
---|
4460 | } while (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);
|
---|
4461 | if (pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {
|
---|
4462 | if (pktin.type != SSH2_MSG_CHANNEL_FAILURE) {
|
---|
4463 | bombout(("Unexpected response to shell/command request:"
|
---|
4464 | " packet type %d", pktin.type));
|
---|
4465 | crReturnV;
|
---|
4466 | }
|
---|
4467 | /*
|
---|
4468 | * We failed to start the command. If this is the
|
---|
4469 | * fallback command, we really are finished; if it's
|
---|
4470 | * not, and if the fallback command exists, try falling
|
---|
4471 | * back to it before complaining.
|
---|
4472 | */
|
---|
4473 | if (!ssh_fallback_cmd && cfg.remote_cmd_ptr2 != NULL) {
|
---|
4474 | logevent("Primary command failed; attempting fallback");
|
---|
4475 | ssh_fallback_cmd = TRUE;
|
---|
4476 | continue;
|
---|
4477 | }
|
---|
4478 | bombout(("Server refused to start a shell/command"));
|
---|
4479 | crReturnV;
|
---|
4480 | } else {
|
---|
4481 | logevent("Started a shell/command");
|
---|
4482 | }
|
---|
4483 | break;
|
---|
4484 | }
|
---|
4485 |
|
---|
4486 | ssh_state = SSH_STATE_SESSION;
|
---|
4487 | if (size_needed)
|
---|
4488 | ssh_size();
|
---|
4489 | if (eof_needed)
|
---|
4490 | ssh_special(TS_EOF);
|
---|
4491 |
|
---|
4492 | /*
|
---|
4493 | * Transfer data!
|
---|
4494 | */
|
---|
4495 | ldisc_send(NULL, 0, 0); /* cause ldisc to notice changes */
|
---|
4496 | ssh_send_ok = 1;
|
---|
4497 | while (1) {
|
---|
4498 | static int try_send;
|
---|
4499 | crReturnV;
|
---|
4500 | try_send = FALSE;
|
---|
4501 | if (ispkt) {
|
---|
4502 | if (pktin.type == SSH2_MSG_CHANNEL_DATA ||
|
---|
4503 | pktin.type == SSH2_MSG_CHANNEL_EXTENDED_DATA) {
|
---|
4504 | char *data;
|
---|
4505 | int length;
|
---|
4506 | unsigned i = ssh2_pkt_getuint32();
|
---|
4507 | struct ssh_channel *c;
|
---|
4508 | c = find234(ssh_channels, &i, ssh_channelfind);
|
---|
4509 | if (!c)
|
---|
4510 | continue; /* nonexistent channel */
|
---|
4511 | if (pktin.type == SSH2_MSG_CHANNEL_EXTENDED_DATA &&
|
---|
4512 | ssh2_pkt_getuint32() != SSH2_EXTENDED_DATA_STDERR)
|
---|
4513 | continue; /* extended but not stderr */
|
---|
4514 | ssh2_pkt_getstring(&data, &length);
|
---|
4515 | if (data) {
|
---|
4516 | int bufsize;
|
---|
4517 | c->v.v2.locwindow -= length;
|
---|
4518 | switch (c->type) {
|
---|
4519 | case CHAN_MAINSESSION:
|
---|
4520 | bufsize =
|
---|
4521 | from_backend(pktin.type ==
|
---|
4522 | SSH2_MSG_CHANNEL_EXTENDED_DATA,
|
---|
4523 | data, length);
|
---|
4524 | break;
|
---|
4525 | case CHAN_X11:
|
---|
4526 | // bufsize = x11_send(c->u.x11.s, data, length);
|
---|
4527 | break;
|
---|
4528 | case CHAN_SOCKDATA:
|
---|
4529 | bufsize = pfd_send(c->u.pfd.s, data, length);
|
---|
4530 | break;
|
---|
4531 | case CHAN_AGENT:
|
---|
4532 | while (length > 0) {
|
---|
4533 | if (c->u.a.lensofar < 4) {
|
---|
4534 | int l = min(4 - c->u.a.lensofar, length);
|
---|
4535 | memcpy(c->u.a.msglen + c->u.a.lensofar,
|
---|
4536 | data, l);
|
---|
4537 | data += l;
|
---|
4538 | length -= l;
|
---|
4539 | c->u.a.lensofar += l;
|
---|
4540 | }
|
---|
4541 | if (c->u.a.lensofar == 4) {
|
---|
4542 | c->u.a.totallen =
|
---|
4543 | 4 + GET_32BIT(c->u.a.msglen);
|
---|
4544 | c->u.a.message = smalloc(c->u.a.totallen);
|
---|
4545 | memcpy(c->u.a.message, c->u.a.msglen, 4);
|
---|
4546 | }
|
---|
4547 | if (c->u.a.lensofar >= 4 && length > 0) {
|
---|
4548 | int l =
|
---|
4549 | min(c->u.a.totallen - c->u.a.lensofar,
|
---|
4550 | length);
|
---|
4551 | memcpy(c->u.a.message + c->u.a.lensofar,
|
---|
4552 | data, l);
|
---|
4553 | data += l;
|
---|
4554 | length -= l;
|
---|
4555 | c->u.a.lensofar += l;
|
---|
4556 | }
|
---|
4557 | if (c->u.a.lensofar == c->u.a.totallen) {
|
---|
4558 | void *reply, *sentreply;
|
---|
4559 | int replylen;
|
---|
4560 | agent_query(c->u.a.message,
|
---|
4561 | c->u.a.totallen, &reply,
|
---|
4562 | &replylen);
|
---|
4563 | if (reply)
|
---|
4564 | sentreply = reply;
|
---|
4565 | else {
|
---|
4566 | /* Fake SSH_AGENT_FAILURE. */
|
---|
4567 | sentreply = "\0\0\0\1\5";
|
---|
4568 | replylen = 5;
|
---|
4569 | }
|
---|
4570 | ssh2_add_channel_data(c, sentreply,
|
---|
4571 | replylen);
|
---|
4572 | try_send = TRUE;
|
---|
4573 | if (reply)
|
---|
4574 | sfree(reply);
|
---|
4575 | sfree(c->u.a.message);
|
---|
4576 | c->u.a.lensofar = 0;
|
---|
4577 | }
|
---|
4578 | }
|
---|
4579 | bufsize = 0;
|
---|
4580 | break;
|
---|
4581 | }
|
---|
4582 | /*
|
---|
4583 | * If we are not buffering too much data,
|
---|
4584 | * enlarge the window again at the remote side.
|
---|
4585 | */
|
---|
4586 | if (bufsize < OUR_V2_WINSIZE)
|
---|
4587 | ssh2_set_window(c, OUR_V2_WINSIZE - bufsize);
|
---|
4588 | }
|
---|
4589 | } else if (pktin.type == SSH2_MSG_DISCONNECT) {
|
---|
4590 | ssh_state = SSH_STATE_CLOSED;
|
---|
4591 | logevent("Received disconnect message");
|
---|
4592 | crReturnV;
|
---|
4593 | } else if (pktin.type == SSH2_MSG_CHANNEL_EOF) {
|
---|
4594 | unsigned i = ssh2_pkt_getuint32();
|
---|
4595 | struct ssh_channel *c;
|
---|
4596 |
|
---|
4597 | c = find234(ssh_channels, &i, ssh_channelfind);
|
---|
4598 | if (!c)
|
---|
4599 | continue; /* nonexistent channel */
|
---|
4600 |
|
---|
4601 | if (c->type == CHAN_X11) {
|
---|
4602 | /*
|
---|
4603 | * Remote EOF on an X11 channel means we should
|
---|
4604 | * wrap up and close the channel ourselves.
|
---|
4605 | */
|
---|
4606 | // x11_close(c->u.x11.s);
|
---|
4607 | sshfwd_close(c);
|
---|
4608 | } else if (c->type == CHAN_AGENT) {
|
---|
4609 | sshfwd_close(c);
|
---|
4610 | } else if (c->type == CHAN_SOCKDATA) {
|
---|
4611 | pfd_close(c->u.pfd.s);
|
---|
4612 | sshfwd_close(c);
|
---|
4613 | }
|
---|
4614 | } else if (pktin.type == SSH2_MSG_CHANNEL_CLOSE) {
|
---|
4615 | unsigned i = ssh2_pkt_getuint32();
|
---|
4616 | struct ssh_channel *c;
|
---|
4617 |
|
---|
4618 | c = find234(ssh_channels, &i, ssh_channelfind);
|
---|
4619 | if (!c)
|
---|
4620 | continue; /* nonexistent channel */
|
---|
4621 | /* Do pre-close processing on the channel. */
|
---|
4622 | switch (c->type) {
|
---|
4623 | case CHAN_MAINSESSION:
|
---|
4624 | break; /* nothing to see here, move along */
|
---|
4625 | case CHAN_X11:
|
---|
4626 | if (c->u.x11.s != NULL)
|
---|
4627 | // x11_close(c->u.x11.s);
|
---|
4628 | sshfwd_close(c);
|
---|
4629 | break;
|
---|
4630 | case CHAN_AGENT:
|
---|
4631 | sshfwd_close(c);
|
---|
4632 | break;
|
---|
4633 | case CHAN_SOCKDATA:
|
---|
4634 | if (c->u.pfd.s != NULL)
|
---|
4635 | pfd_close(c->u.pfd.s);
|
---|
4636 | sshfwd_close(c);
|
---|
4637 | break;
|
---|
4638 | }
|
---|
4639 | if (c->closes == 0) {
|
---|
4640 | ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE);
|
---|
4641 | ssh2_pkt_adduint32(c->remoteid);
|
---|
4642 | ssh2_pkt_send();
|
---|
4643 | }
|
---|
4644 | del234(ssh_channels, c);
|
---|
4645 | bufchain_clear(&c->v.v2.outbuffer);
|
---|
4646 | sfree(c);
|
---|
4647 |
|
---|
4648 | /*
|
---|
4649 | * See if that was the last channel left open.
|
---|
4650 | */
|
---|
4651 | if (count234(ssh_channels) == 0) {
|
---|
4652 | #if 0
|
---|
4653 | /*
|
---|
4654 | * We used to send SSH_MSG_DISCONNECT here,
|
---|
4655 | * because I'd believed that _every_ conforming
|
---|
4656 | * SSH2 connection had to end with a disconnect
|
---|
4657 | * being sent by at least one side; apparently
|
---|
4658 | * I was wrong and it's perfectly OK to
|
---|
4659 | * unceremoniously slam the connection shut
|
---|
4660 | * when you're done, and indeed OpenSSH feels
|
---|
4661 | * this is more polite than sending a
|
---|
4662 | * DISCONNECT. So now we don't.
|
---|
4663 | */
|
---|
4664 | logevent("All channels closed. Disconnecting");
|
---|
4665 | ssh2_pkt_init(SSH2_MSG_DISCONNECT);
|
---|
4666 | ssh2_pkt_adduint32(SSH2_DISCONNECT_BY_APPLICATION);
|
---|
4667 | ssh2_pkt_addstring("All open channels closed");
|
---|
4668 | ssh2_pkt_addstring("en"); /* language tag */
|
---|
4669 | ssh2_pkt_send();
|
---|
4670 | #endif
|
---|
4671 | ssh_state = SSH_STATE_CLOSED;
|
---|
4672 | crReturnV;
|
---|
4673 | }
|
---|
4674 | continue; /* remote sends close; ignore (FIXME) */
|
---|
4675 | } else if (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {
|
---|
4676 | unsigned i = ssh2_pkt_getuint32();
|
---|
4677 | struct ssh_channel *c;
|
---|
4678 | c = find234(ssh_channels, &i, ssh_channelfind);
|
---|
4679 | if (!c)
|
---|
4680 | continue; /* nonexistent channel */
|
---|
4681 | c->v.v2.remwindow += ssh2_pkt_getuint32();
|
---|
4682 | try_send = TRUE;
|
---|
4683 | } else if (pktin.type == SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {
|
---|
4684 | unsigned i = ssh2_pkt_getuint32();
|
---|
4685 | struct ssh_channel *c;
|
---|
4686 | c = find234(ssh_channels, &i, ssh_channelfind);
|
---|
4687 | if (!c)
|
---|
4688 | continue; /* nonexistent channel */
|
---|
4689 | if (c->type != CHAN_SOCKDATA_DORMANT)
|
---|
4690 | continue; /* dunno why they're confirming this */
|
---|
4691 | c->remoteid = ssh2_pkt_getuint32();
|
---|
4692 | c->type = CHAN_SOCKDATA;
|
---|
4693 | c->v.v2.remwindow = ssh2_pkt_getuint32();
|
---|
4694 | c->v.v2.remmaxpkt = ssh2_pkt_getuint32();
|
---|
4695 | if (c->u.pfd.s)
|
---|
4696 | pfd_confirm(c->u.pfd.s);
|
---|
4697 | if (c->closes) {
|
---|
4698 | /*
|
---|
4699 | * We have a pending close on this channel,
|
---|
4700 | * which we decided on before the server acked
|
---|
4701 | * the channel open. So now we know the
|
---|
4702 | * remoteid, we can close it again.
|
---|
4703 | */
|
---|
4704 | ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE);
|
---|
4705 | ssh2_pkt_adduint32(c->remoteid);
|
---|
4706 | ssh2_pkt_send();
|
---|
4707 | }
|
---|
4708 | } else if (pktin.type == SSH2_MSG_CHANNEL_OPEN_FAILURE) {
|
---|
4709 | unsigned i = ssh2_pkt_getuint32();
|
---|
4710 | struct ssh_channel *c;
|
---|
4711 | c = find234(ssh_channels, &i, ssh_channelfind);
|
---|
4712 | if (!c)
|
---|
4713 | continue; /* nonexistent channel */
|
---|
4714 | if (c->type != CHAN_SOCKDATA_DORMANT)
|
---|
4715 | continue; /* dunno why they're failing this */
|
---|
4716 |
|
---|
4717 | logevent("Forwarded connection refused by server");
|
---|
4718 |
|
---|
4719 | pfd_close(c->u.pfd.s);
|
---|
4720 |
|
---|
4721 | del234(ssh_channels, c);
|
---|
4722 | sfree(c);
|
---|
4723 | } else if (pktin.type == SSH2_MSG_CHANNEL_REQUEST) {
|
---|
4724 | unsigned localid;
|
---|
4725 | char *type;
|
---|
4726 | int typelen, want_reply;
|
---|
4727 | struct ssh_channel *c;
|
---|
4728 |
|
---|
4729 | localid = ssh2_pkt_getuint32();
|
---|
4730 | ssh2_pkt_getstring(&type, &typelen);
|
---|
4731 | want_reply = ssh2_pkt_getbool();
|
---|
4732 |
|
---|
4733 | /*
|
---|
4734 | * First, check that the channel exists. Otherwise,
|
---|
4735 | * we can instantly disconnect with a rude message.
|
---|
4736 | */
|
---|
4737 | c = find234(ssh_channels, &localid, ssh_channelfind);
|
---|
4738 | if (!c) {
|
---|
4739 | char buf[80];
|
---|
4740 | sprintf(buf, "Received channel request for nonexistent"
|
---|
4741 | " channel %d", localid);
|
---|
4742 | logevent(buf);
|
---|
4743 | ssh2_pkt_init(SSH2_MSG_DISCONNECT);
|
---|
4744 | ssh2_pkt_adduint32(SSH2_DISCONNECT_BY_APPLICATION);
|
---|
4745 | ssh2_pkt_addstring(buf);
|
---|
4746 | ssh2_pkt_addstring("en"); /* language tag */
|
---|
4747 | ssh2_pkt_send();
|
---|
4748 | connection_fatal(buf);
|
---|
4749 | ssh_state = SSH_STATE_CLOSED;
|
---|
4750 | crReturnV;
|
---|
4751 | }
|
---|
4752 |
|
---|
4753 | /*
|
---|
4754 | * Having got the channel number, we now look at
|
---|
4755 | * the request type string to see if it's something
|
---|
4756 | * we recognise.
|
---|
4757 | */
|
---|
4758 | if (typelen == 11 && !memcmp(type, "exit-status", 11) &&
|
---|
4759 | c == mainchan) {
|
---|
4760 | /* We recognise "exit-status" on the primary channel. */
|
---|
4761 | char buf[100];
|
---|
4762 | ssh_exitcode = ssh2_pkt_getuint32();
|
---|
4763 | sprintf(buf, "Server sent command exit status %d",
|
---|
4764 | ssh_exitcode);
|
---|
4765 | logevent(buf);
|
---|
4766 | if (want_reply) {
|
---|
4767 | ssh2_pkt_init(SSH2_MSG_CHANNEL_SUCCESS);
|
---|
4768 | ssh2_pkt_adduint32(c->remoteid);
|
---|
4769 | ssh2_pkt_send();
|
---|
4770 | }
|
---|
4771 | } else {
|
---|
4772 | /*
|
---|
4773 | * This is a channel request we don't know
|
---|
4774 | * about, so we now either ignore the request
|
---|
4775 | * or respond with CHANNEL_FAILURE, depending
|
---|
4776 | * on want_reply.
|
---|
4777 | */
|
---|
4778 | if (want_reply) {
|
---|
4779 | ssh2_pkt_init(SSH2_MSG_CHANNEL_FAILURE);
|
---|
4780 | ssh2_pkt_adduint32(c->remoteid);
|
---|
4781 | ssh2_pkt_send();
|
---|
4782 | }
|
---|
4783 | }
|
---|
4784 | } else if (pktin.type == SSH2_MSG_GLOBAL_REQUEST) {
|
---|
4785 | char *type;
|
---|
4786 | int typelen, want_reply;
|
---|
4787 |
|
---|
4788 | ssh2_pkt_getstring(&type, &typelen);
|
---|
4789 | want_reply = ssh2_pkt_getbool();
|
---|
4790 |
|
---|
4791 | /*
|
---|
4792 | * We currently don't support any global requests
|
---|
4793 | * at all, so we either ignore the request or
|
---|
4794 | * respond with REQUEST_FAILURE, depending on
|
---|
4795 | * want_reply.
|
---|
4796 | */
|
---|
4797 | if (want_reply) {
|
---|
4798 | ssh2_pkt_init(SSH2_MSG_REQUEST_FAILURE);
|
---|
4799 | ssh2_pkt_send();
|
---|
4800 | }
|
---|
4801 | } else if (pktin.type == SSH2_MSG_CHANNEL_OPEN) {
|
---|
4802 | char *type;
|
---|
4803 | int typelen;
|
---|
4804 | char *error = NULL;
|
---|
4805 | struct ssh_channel *c;
|
---|
4806 | unsigned remid, winsize, pktsize;
|
---|
4807 | ssh2_pkt_getstring(&type, &typelen);
|
---|
4808 | c = smalloc(sizeof(struct ssh_channel));
|
---|
4809 |
|
---|
4810 | remid = ssh2_pkt_getuint32();
|
---|
4811 | winsize = ssh2_pkt_getuint32();
|
---|
4812 | pktsize = ssh2_pkt_getuint32();
|
---|
4813 |
|
---|
4814 | if (typelen == 3 && !memcmp(type, "x11", 3)) {
|
---|
4815 | // if (!ssh_X11_fwd_enabled)
|
---|
4816 | error = "X11 forwarding is not enabled";
|
---|
4817 | /* else if (x11_init(&c->u.x11.s, cfg.x11_display, c) !=
|
---|
4818 | NULL) {
|
---|
4819 | error = "Unable to open an X11 connection";
|
---|
4820 | //} else {
|
---|
4821 | c->type = CHAN_X11;
|
---|
4822 | }*/
|
---|
4823 | } else if (typelen == 15 &&
|
---|
4824 | !memcmp(type, "forwarded-tcpip", 15)) {
|
---|
4825 | struct ssh_rportfwd pf;
|
---|
4826 | char *dummy;
|
---|
4827 | int dummylen;
|
---|
4828 | ssh2_pkt_getstring(&dummy, &dummylen);/* skip address */
|
---|
4829 | pf.sport = ssh2_pkt_getuint32();
|
---|
4830 | error = "Remote port is not recognised";
|
---|
4831 | } else if (typelen == 22 &&
|
---|
4832 | !memcmp(type, "auth-agent@openssh.com", 3)) {
|
---|
4833 | if (!ssh_agentfwd_enabled)
|
---|
4834 | error = "Agent forwarding is not enabled";
|
---|
4835 | else {
|
---|
4836 | c->type = CHAN_AGENT; /* identify channel type */
|
---|
4837 | c->u.a.lensofar = 0;
|
---|
4838 | }
|
---|
4839 | } else {
|
---|
4840 | error = "Unsupported channel type requested";
|
---|
4841 | }
|
---|
4842 |
|
---|
4843 | c->remoteid = remid;
|
---|
4844 | if (error) {
|
---|
4845 | ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN_FAILURE);
|
---|
4846 | ssh2_pkt_adduint32(c->remoteid);
|
---|
4847 | ssh2_pkt_adduint32(SSH2_OPEN_CONNECT_FAILED);
|
---|
4848 | ssh2_pkt_addstring(error);
|
---|
4849 | ssh2_pkt_addstring("en"); /* language tag */
|
---|
4850 | ssh2_pkt_send();
|
---|
4851 | sfree(c);
|
---|
4852 | } else {
|
---|
4853 | c->localid = alloc_channel_id();
|
---|
4854 | c->closes = 0;
|
---|
4855 | c->v.v2.locwindow = OUR_V2_WINSIZE;
|
---|
4856 | c->v.v2.remwindow = winsize;
|
---|
4857 | c->v.v2.remmaxpkt = pktsize;
|
---|
4858 | bufchain_init(&c->v.v2.outbuffer);
|
---|
4859 | add234(ssh_channels, c);
|
---|
4860 | ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
|
---|
4861 | ssh2_pkt_adduint32(c->remoteid);
|
---|
4862 | ssh2_pkt_adduint32(c->localid);
|
---|
4863 | ssh2_pkt_adduint32(c->v.v2.locwindow);
|
---|
4864 | ssh2_pkt_adduint32(0x4000UL); /* our max pkt size */
|
---|
4865 | ssh2_pkt_send();
|
---|
4866 | }
|
---|
4867 | } else {
|
---|
4868 | bombout(("Strange packet received: type %d", pktin.type));
|
---|
4869 | crReturnV;
|
---|
4870 | }
|
---|
4871 | } else {
|
---|
4872 | /*
|
---|
4873 | * We have spare data. Add it to the channel buffer.
|
---|
4874 | */
|
---|
4875 | ssh2_add_channel_data(mainchan, in, inlen);
|
---|
4876 | try_send = TRUE;
|
---|
4877 | }
|
---|
4878 | if (try_send) {
|
---|
4879 | int i;
|
---|
4880 | struct ssh_channel *c;
|
---|
4881 | /*
|
---|
4882 | * Try to send data on all channels if we can.
|
---|
4883 | */
|
---|
4884 | for (i = 0; NULL != (c = index234(ssh_channels, i)); i++) {
|
---|
4885 | int bufsize = ssh2_try_send(c);
|
---|
4886 | if (bufsize == 0) {
|
---|
4887 | switch (c->type) {
|
---|
4888 | case CHAN_MAINSESSION:
|
---|
4889 | /* stdin need not receive an unthrottle
|
---|
4890 | * notification since it will be polled */
|
---|
4891 | break;
|
---|
4892 | case CHAN_X11:
|
---|
4893 | // x11_unthrottle(c->u.x11.s);
|
---|
4894 | break;
|
---|
4895 | case CHAN_AGENT:
|
---|
4896 | /* agent sockets are request/response and need no
|
---|
4897 | * buffer management */
|
---|
4898 | break;
|
---|
4899 | case CHAN_SOCKDATA:
|
---|
4900 | pfd_unthrottle(c->u.pfd.s);
|
---|
4901 | break;
|
---|
4902 | }
|
---|
4903 | }
|
---|
4904 | }
|
---|
4905 | }
|
---|
4906 | }
|
---|
4907 |
|
---|
4908 | crFinishV;
|
---|
4909 | }
|
---|
4910 |
|
---|
4911 | /*
|
---|
4912 | * Handle the top-level SSH2 protocol.
|
---|
4913 | */
|
---|
4914 | static void ssh2_protocol(unsigned char *in, int inlen, int ispkt)
|
---|
4915 | {
|
---|
4916 | if (do_ssh2_transport(in, inlen, ispkt) == 0)
|
---|
4917 | return;
|
---|
4918 | do_ssh2_authconn(in, inlen, ispkt);
|
---|
4919 | }
|
---|
4920 |
|
---|
4921 | /*
|
---|
4922 | * Called to set up the connection.
|
---|
4923 | *
|
---|
4924 | * Returns an error message, or NULL on success.
|
---|
4925 | */
|
---|
4926 | static char *ssh_init(char *host, int port, char **realhost, int nodelay)
|
---|
4927 | {
|
---|
4928 | char *p;
|
---|
4929 |
|
---|
4930 | #ifdef MSCRYPTOAPI
|
---|
4931 | if (crypto_startup() == 0)
|
---|
4932 | return "Microsoft high encryption pack not installed!";
|
---|
4933 | #endif
|
---|
4934 |
|
---|
4935 | ssh_send_ok = 0;
|
---|
4936 | ssh_editing = 0;
|
---|
4937 | ssh_echoing = 0;
|
---|
4938 | ssh1_throttle_count = 0;
|
---|
4939 | ssh_overall_bufsize = 0;
|
---|
4940 | ssh_fallback_cmd = 0;
|
---|
4941 |
|
---|
4942 | p = connect_to_host(host, port, realhost, nodelay);
|
---|
4943 | if (p != NULL)
|
---|
4944 | return p;
|
---|
4945 |
|
---|
4946 | return NULL;
|
---|
4947 | }
|
---|
4948 |
|
---|
4949 | /*
|
---|
4950 | * Called to send data down the Telnet connection.
|
---|
4951 | */
|
---|
4952 | static int ssh_send(char *buf, int len)
|
---|
4953 | {
|
---|
4954 | if (s == NULL || ssh_protocol == NULL)
|
---|
4955 | return 0;
|
---|
4956 |
|
---|
4957 | ssh_protocol(buf, len, 0);
|
---|
4958 |
|
---|
4959 | return ssh_sendbuffer();
|
---|
4960 | }
|
---|
4961 |
|
---|
4962 | /*
|
---|
4963 | * Called to query the current amount of buffered stdin data.
|
---|
4964 | */
|
---|
4965 | static int ssh_sendbuffer(void)
|
---|
4966 | {
|
---|
4967 | int override_value;
|
---|
4968 |
|
---|
4969 | if (s == NULL || ssh_protocol == NULL)
|
---|
4970 | return 0;
|
---|
4971 |
|
---|
4972 | /*
|
---|
4973 | * If the SSH socket itself has backed up, add the total backup
|
---|
4974 | * size on that to any individual buffer on the stdin channel.
|
---|
4975 | */
|
---|
4976 | override_value = 0;
|
---|
4977 | if (ssh_throttled_all)
|
---|
4978 | override_value = ssh_overall_bufsize;
|
---|
4979 |
|
---|
4980 | if (ssh_version == 1) {
|
---|
4981 | return override_value;
|
---|
4982 | } else if (ssh_version == 2) {
|
---|
4983 | if (!mainchan || mainchan->closes > 0)
|
---|
4984 | return override_value;
|
---|
4985 | else
|
---|
4986 | return override_value + bufchain_size(&mainchan->v.v2.outbuffer);
|
---|
4987 | }
|
---|
4988 |
|
---|
4989 | return 0;
|
---|
4990 | }
|
---|
4991 |
|
---|
4992 | /*
|
---|
4993 | * Called to set the size of the window from SSH's POV.
|
---|
4994 | */
|
---|
4995 | static void ssh_size(void)
|
---|
4996 | {
|
---|
4997 | switch (ssh_state) {
|
---|
4998 | case SSH_STATE_BEFORE_SIZE:
|
---|
4999 | case SSH_STATE_PREPACKET:
|
---|
5000 | case SSH_STATE_CLOSED:
|
---|
5001 | break; /* do nothing */
|
---|
5002 | case SSH_STATE_INTERMED:
|
---|
5003 | size_needed = TRUE; /* buffer for later */
|
---|
5004 | break;
|
---|
5005 | case SSH_STATE_SESSION:
|
---|
5006 | if (!cfg.nopty) {
|
---|
5007 | if (ssh_version == 1) {
|
---|
5008 | send_packet(SSH1_CMSG_WINDOW_SIZE,
|
---|
5009 | PKT_INT, rows, PKT_INT, cols,
|
---|
5010 | PKT_INT, 0, PKT_INT, 0, PKT_END);
|
---|
5011 | } else {
|
---|
5012 | ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
|
---|
5013 | ssh2_pkt_adduint32(mainchan->remoteid);
|
---|
5014 | ssh2_pkt_addstring("window-change");
|
---|
5015 | ssh2_pkt_addbool(0);
|
---|
5016 | ssh2_pkt_adduint32(cols);
|
---|
5017 | ssh2_pkt_adduint32(rows);
|
---|
5018 | ssh2_pkt_adduint32(0);
|
---|
5019 | ssh2_pkt_adduint32(0);
|
---|
5020 | ssh2_pkt_send();
|
---|
5021 | }
|
---|
5022 | }
|
---|
5023 | break;
|
---|
5024 | }
|
---|
5025 | }
|
---|
5026 |
|
---|
5027 | /*
|
---|
5028 | * Send Telnet special codes. TS_EOF is useful for `plink', so you
|
---|
5029 | * can send an EOF and collect resulting output (e.g. `plink
|
---|
5030 | * hostname sort').
|
---|
5031 | */
|
---|
5032 | static void ssh_special(Telnet_Special code)
|
---|
5033 | {
|
---|
5034 | if (code == TS_EOF) {
|
---|
5035 | if (ssh_state != SSH_STATE_SESSION) {
|
---|
5036 | /*
|
---|
5037 | * Buffer the EOF in case we are pre-SESSION, so we can
|
---|
5038 | * send it as soon as we reach SESSION.
|
---|
5039 | */
|
---|
5040 | if (code == TS_EOF)
|
---|
5041 | eof_needed = TRUE;
|
---|
5042 | return;
|
---|
5043 | }
|
---|
5044 | if (ssh_version == 1) {
|
---|
5045 | send_packet(SSH1_CMSG_EOF, PKT_END);
|
---|
5046 | } else {
|
---|
5047 | ssh2_pkt_init(SSH2_MSG_CHANNEL_EOF);
|
---|
5048 | ssh2_pkt_adduint32(mainchan->remoteid);
|
---|
5049 | ssh2_pkt_send();
|
---|
5050 | }
|
---|
5051 | logevent("Sent EOF message");
|
---|
5052 | } else if (code == TS_PING) {
|
---|
5053 | if (ssh_state == SSH_STATE_CLOSED
|
---|
5054 | || ssh_state == SSH_STATE_PREPACKET) return;
|
---|
5055 | if (ssh_version == 1) {
|
---|
5056 | send_packet(SSH1_MSG_IGNORE, PKT_STR, "", PKT_END);
|
---|
5057 | } else {
|
---|
5058 | ssh2_pkt_init(SSH2_MSG_IGNORE);
|
---|
5059 | ssh2_pkt_addstring_start();
|
---|
5060 | ssh2_pkt_send();
|
---|
5061 | }
|
---|
5062 | } else {
|
---|
5063 | /* do nothing */
|
---|
5064 | }
|
---|
5065 | }
|
---|
5066 |
|
---|
5067 | void *new_sock_channel(Socket s)
|
---|
5068 | {
|
---|
5069 | struct ssh_channel *c;
|
---|
5070 | c = smalloc(sizeof(struct ssh_channel));
|
---|
5071 |
|
---|
5072 | if (c) {
|
---|
5073 | c->remoteid = -1; /* to be set when open confirmed */
|
---|
5074 | c->localid = alloc_channel_id();
|
---|
5075 | c->closes = 0;
|
---|
5076 | c->type = CHAN_SOCKDATA_DORMANT;/* identify channel type */
|
---|
5077 | c->u.pfd.s = s;
|
---|
5078 | bufchain_init(&c->v.v2.outbuffer);
|
---|
5079 | add234(ssh_channels, c);
|
---|
5080 | }
|
---|
5081 | return c;
|
---|
5082 | }
|
---|
5083 |
|
---|
5084 | /*
|
---|
5085 | * This is called when stdout/stderr (the entity to which
|
---|
5086 | * from_backend sends data) manages to clear some backlog.
|
---|
5087 | */
|
---|
5088 | void ssh_unthrottle(int bufsize)
|
---|
5089 | {
|
---|
5090 | if (ssh_version == 1) {
|
---|
5091 | if (ssh1_stdout_throttling && bufsize < SSH1_BUFFER_LIMIT) {
|
---|
5092 | ssh1_stdout_throttling = 0;
|
---|
5093 | ssh1_throttle(-1);
|
---|
5094 | }
|
---|
5095 | } else {
|
---|
5096 | if (mainchan && mainchan->closes == 0)
|
---|
5097 | ssh2_set_window(mainchan, OUR_V2_WINSIZE - bufsize);
|
---|
5098 | }
|
---|
5099 | }
|
---|
5100 |
|
---|
5101 | void ssh_send_port_open(void *channel, char *hostname, int port, char *org)
|
---|
5102 | {
|
---|
5103 | struct ssh_channel *c = (struct ssh_channel *)channel;
|
---|
5104 | char buf[1024];
|
---|
5105 |
|
---|
5106 | sprintf(buf, "Opening forwarded connection to %.512s:%d", hostname, port);
|
---|
5107 | logevent(buf);
|
---|
5108 |
|
---|
5109 | if (ssh_version == 1) {
|
---|
5110 | send_packet(SSH1_MSG_PORT_OPEN,
|
---|
5111 | PKT_INT, c->localid,
|
---|
5112 | PKT_STR, hostname,
|
---|
5113 | PKT_INT, port,
|
---|
5114 | //PKT_STR, <org:orgport>,
|
---|
5115 | PKT_END);
|
---|
5116 | } else {
|
---|
5117 | ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);
|
---|
5118 | ssh2_pkt_addstring("direct-tcpip");
|
---|
5119 | ssh2_pkt_adduint32(c->localid);
|
---|
5120 | c->v.v2.locwindow = OUR_V2_WINSIZE;
|
---|
5121 | ssh2_pkt_adduint32(c->v.v2.locwindow);/* our window size */
|
---|
5122 | ssh2_pkt_adduint32(0x4000UL); /* our max pkt size */
|
---|
5123 | ssh2_pkt_addstring(hostname);
|
---|
5124 | ssh2_pkt_adduint32(port);
|
---|
5125 | /*
|
---|
5126 | * We make up values for the originator data; partly it's
|
---|
5127 | * too much hassle to keep track, and partly I'm not
|
---|
5128 | * convinced the server should be told details like that
|
---|
5129 | * about my local network configuration.
|
---|
5130 | */
|
---|
5131 | ssh2_pkt_addstring("client-side-connection");
|
---|
5132 | ssh2_pkt_adduint32(0);
|
---|
5133 | ssh2_pkt_send();
|
---|
5134 | }
|
---|
5135 | }
|
---|
5136 |
|
---|
5137 |
|
---|
5138 | static Socket ssh_socket(void)
|
---|
5139 | {
|
---|
5140 | return s;
|
---|
5141 | }
|
---|
5142 |
|
---|
5143 | static int ssh_sendok(void)
|
---|
5144 | {
|
---|
5145 | return ssh_send_ok;
|
---|
5146 | }
|
---|
5147 |
|
---|
5148 | static int ssh_ldisc(int option)
|
---|
5149 | {
|
---|
5150 | if (option == LD_ECHO)
|
---|
5151 | return ssh_echoing;
|
---|
5152 | if (option == LD_EDIT)
|
---|
5153 | return ssh_editing;
|
---|
5154 | return FALSE;
|
---|
5155 | }
|
---|
5156 |
|
---|
5157 | static int ssh_return_exitcode(void)
|
---|
5158 | {
|
---|
5159 | return ssh_exitcode;
|
---|
5160 | }
|
---|
5161 |
|
---|
5162 | Backend ssh_backend = {
|
---|
5163 | ssh_init,
|
---|
5164 | ssh_send,
|
---|
5165 | ssh_sendbuffer,
|
---|
5166 | ssh_size,
|
---|
5167 | ssh_special,
|
---|
5168 | ssh_socket,
|
---|
5169 | ssh_return_exitcode,
|
---|
5170 | ssh_sendok,
|
---|
5171 | ssh_ldisc,
|
---|
5172 | ssh_unthrottle,
|
---|
5173 | 22
|
---|
5174 | };
|
---|
5175 |
|
---|
5176 |
|
---|