Mercurial > dropbear
comparison cli-session.c @ 801:7dcb46da72d9 ecc
merge in HEAD
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Tue, 21 May 2013 12:09:35 +0800 |
parents | 7f604f9b3756 2400b8685762 |
children | c19acba28590 |
comparison
equal
deleted
inserted
replaced
799:c344607b7341 | 801:7dcb46da72d9 |
---|---|
40 | 40 |
41 static void cli_remoteclosed(); | 41 static void cli_remoteclosed(); |
42 static void cli_sessionloop(); | 42 static void cli_sessionloop(); |
43 static void cli_session_init(); | 43 static void cli_session_init(); |
44 static void cli_finished(); | 44 static void cli_finished(); |
45 static void recv_msg_service_accept(void); | |
46 static void cli_session_cleanup(void); | |
45 | 47 |
46 struct clientsession cli_ses; /* GLOBAL */ | 48 struct clientsession cli_ses; /* GLOBAL */ |
47 | 49 |
48 /* Sorted in decreasing frequency will be more efficient - data and window | 50 /* Sorted in decreasing frequency will be more efficient - data and window |
49 * should be first */ | 51 * should be first */ |
94 | 96 |
95 /* Ready to go */ | 97 /* Ready to go */ |
96 sessinitdone = 1; | 98 sessinitdone = 1; |
97 | 99 |
98 /* Exchange identification */ | 100 /* Exchange identification */ |
99 session_identification(); | 101 send_session_identification(); |
100 | 102 |
101 send_msg_kexinit(); | 103 send_msg_kexinit(); |
102 | 104 |
103 session_loop(cli_sessionloop); | 105 session_loop(cli_sessionloop); |
104 | 106 |
105 /* Not reached */ | 107 /* Not reached */ |
106 | 108 |
107 } | 109 } |
110 | |
111 #ifdef USE_KEX_FIRST_FOLLOWS | |
112 static void cli_send_kex_first_guess() { | |
113 send_msg_kexdh_init(); | |
114 } | |
115 #endif | |
108 | 116 |
109 static void cli_session_init() { | 117 static void cli_session_init() { |
110 | 118 |
111 cli_ses.state = STATE_NOTHING; | 119 cli_ses.state = STATE_NOTHING; |
112 cli_ses.kex_state = KEX_NOTHING; | 120 cli_ses.kex_state = KEX_NOTHING; |
137 cli_ses.cipher_none_after_auth = 0; | 145 cli_ses.cipher_none_after_auth = 0; |
138 #endif | 146 #endif |
139 | 147 |
140 /* For printing "remote host closed" for the user */ | 148 /* For printing "remote host closed" for the user */ |
141 ses.remoteclosed = cli_remoteclosed; | 149 ses.remoteclosed = cli_remoteclosed; |
142 ses.buf_match_algo = cli_buf_match_algo; | 150 |
151 ses.extra_session_cleanup = cli_session_cleanup; | |
143 | 152 |
144 /* packet handlers */ | 153 /* packet handlers */ |
145 ses.packettypes = cli_packettypes; | 154 ses.packettypes = cli_packettypes; |
146 | 155 |
147 ses.isserver = 0; | 156 ses.isserver = 0; |
157 | |
158 #ifdef USE_KEX_FIRST_FOLLOWS | |
159 ses.send_kex_first_guess = cli_send_kex_first_guess; | |
160 #endif | |
161 | |
162 } | |
163 | |
164 static void send_msg_service_request(char* servicename) { | |
165 | |
166 TRACE(("enter send_msg_service_request: servicename='%s'", servicename)) | |
167 | |
168 CHECKCLEARTOWRITE(); | |
169 | |
170 buf_putbyte(ses.writepayload, SSH_MSG_SERVICE_REQUEST); | |
171 buf_putstring(ses.writepayload, servicename, strlen(servicename)); | |
172 | |
173 encrypt_packet(); | |
174 TRACE(("leave send_msg_service_request")) | |
175 } | |
176 | |
177 static void recv_msg_service_accept(void) { | |
178 // do nothing, if it failed then the server MUST have disconnected | |
148 } | 179 } |
149 | 180 |
150 /* This function drives the progress of the session - it initiates KEX, | 181 /* This function drives the progress of the session - it initiates KEX, |
151 * service, userauth and channel requests */ | 182 * service, userauth and channel requests */ |
152 static void cli_sessionloop() { | 183 static void cli_sessionloop() { |
153 | 184 |
154 TRACE(("enter cli_sessionloop")) | 185 TRACE2(("enter cli_sessionloop")) |
186 | |
187 if (ses.lastpacket == 0) { | |
188 TRACE2(("exit cli_sessionloop: no real packets yet")) | |
189 return; | |
190 } | |
155 | 191 |
156 if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) { | 192 if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) { |
157 cli_ses.kex_state = KEXINIT_RCVD; | |
158 } | |
159 | |
160 if (cli_ses.kex_state == KEXINIT_RCVD) { | |
161 | |
162 /* We initiate the KEXDH. If DH wasn't the correct type, the KEXINIT | 193 /* We initiate the KEXDH. If DH wasn't the correct type, the KEXINIT |
163 * negotiation would have failed. */ | 194 * negotiation would have failed. */ |
164 send_msg_kexdh_init(); | 195 if (!ses.kexstate.our_first_follows_matches) { |
165 cli_ses.kex_state = KEXDH_INIT_SENT; | 196 send_msg_kexdh_init(); |
197 } | |
198 cli_ses.kex_state = KEXDH_INIT_SENT; | |
166 TRACE(("leave cli_sessionloop: done with KEXINIT_RCVD")) | 199 TRACE(("leave cli_sessionloop: done with KEXINIT_RCVD")) |
167 return; | 200 return; |
168 } | 201 } |
169 | 202 |
170 /* A KEX has finished, so we should go back to our KEX_NOTHING state */ | 203 /* A KEX has finished, so we should go back to our KEX_NOTHING state */ |
171 if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.recvkexinit == 0 | 204 if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.sentnewkeys) { |
172 && ses.kexstate.sentkexinit == 0) { | |
173 cli_ses.kex_state = KEX_NOTHING; | 205 cli_ses.kex_state = KEX_NOTHING; |
174 } | 206 } |
175 | 207 |
176 /* We shouldn't do anything else if a KEX is in progress */ | 208 /* We shouldn't do anything else if a KEX is in progress */ |
177 if (cli_ses.kex_state != KEX_NOTHING) { | 209 if (cli_ses.kex_state != KEX_NOTHING) { |
178 TRACE(("leave cli_sessionloop: kex_state != KEX_NOTHING")) | 210 TRACE(("leave cli_sessionloop: kex_state != KEX_NOTHING")) |
179 return; | 211 return; |
180 } | 212 } |
181 | 213 |
182 /* We should exit if we haven't donefirstkex: we shouldn't reach here | |
183 * in normal operation */ | |
184 if (ses.kexstate.donefirstkex == 0) { | 214 if (ses.kexstate.donefirstkex == 0) { |
185 TRACE(("XXX XXX might be bad! leave cli_sessionloop: haven't donefirstkex")) | 215 /* We might reach here if we have partial packet reads or have |
216 * received SSG_MSG_IGNORE etc. Just skip it */ | |
217 TRACE2(("donefirstkex false\n")) | |
186 return; | 218 return; |
187 } | 219 } |
188 | 220 |
189 switch (cli_ses.state) { | 221 switch (cli_ses.state) { |
190 | 222 |
191 case STATE_NOTHING: | 223 case STATE_NOTHING: |
192 /* We've got the transport layer sorted, we now need to request | 224 /* We've got the transport layer sorted, we now need to request |
193 * userauth */ | 225 * userauth */ |
194 send_msg_service_request(SSH_SERVICE_USERAUTH); | 226 send_msg_service_request(SSH_SERVICE_USERAUTH); |
195 cli_ses.state = SERVICE_AUTH_REQ_SENT; | |
196 TRACE(("leave cli_sessionloop: sent userauth service req")) | |
197 return; | |
198 | |
199 /* userauth code */ | |
200 case SERVICE_AUTH_ACCEPT_RCVD: | |
201 cli_auth_getmethods(); | 227 cli_auth_getmethods(); |
202 cli_ses.state = USERAUTH_REQ_SENT; | 228 cli_ses.state = USERAUTH_REQ_SENT; |
203 TRACE(("leave cli_sessionloop: sent userauth methods req")) | 229 TRACE(("leave cli_sessionloop: sent userauth methods req")) |
204 return; | 230 return; |
205 | 231 |
206 case USERAUTH_FAIL_RCVD: | 232 case USERAUTH_FAIL_RCVD: |
207 cli_auth_try(); | 233 if (cli_auth_try() == DROPBEAR_FAILURE) { |
234 dropbear_exit("No auth methods could be used."); | |
235 } | |
208 cli_ses.state = USERAUTH_REQ_SENT; | 236 cli_ses.state = USERAUTH_REQ_SENT; |
209 TRACE(("leave cli_sessionloop: cli_auth_try")) | 237 TRACE(("leave cli_sessionloop: cli_auth_try")) |
210 return; | 238 return; |
211 | 239 |
212 case USERAUTH_SUCCESS_RCVD: | 240 case USERAUTH_SUCCESS_RCVD: |
233 dropbear_exit("Backgrounding failed: %d %s", | 261 dropbear_exit("Backgrounding failed: %d %s", |
234 errno, strerror(errno)); | 262 errno, strerror(errno)); |
235 } | 263 } |
236 } | 264 } |
237 | 265 |
238 #ifdef ENABLE_CLI_LOCALTCPFWD | |
239 setup_localtcp(); | |
240 #endif | |
241 #ifdef ENABLE_CLI_REMOTETCPFWD | |
242 setup_remotetcp(); | |
243 #endif | |
244 | |
245 #ifdef ENABLE_CLI_NETCAT | 266 #ifdef ENABLE_CLI_NETCAT |
246 if (cli_opts.netcat_host) { | 267 if (cli_opts.netcat_host) { |
247 cli_send_netcat_request(); | 268 cli_send_netcat_request(); |
248 } else | 269 } else |
249 #endif | 270 #endif |
250 if (!cli_opts.no_cmd) { | 271 if (!cli_opts.no_cmd) { |
251 cli_send_chansess_request(); | 272 cli_send_chansess_request(); |
252 } | 273 } |
274 | |
275 #ifdef ENABLE_CLI_LOCALTCPFWD | |
276 setup_localtcp(); | |
277 #endif | |
278 #ifdef ENABLE_CLI_REMOTETCPFWD | |
279 setup_remotetcp(); | |
280 #endif | |
281 | |
253 TRACE(("leave cli_sessionloop: running")) | 282 TRACE(("leave cli_sessionloop: running")) |
254 cli_ses.state = SESSION_RUNNING; | 283 cli_ses.state = SESSION_RUNNING; |
255 return; | 284 return; |
256 | 285 |
257 case SESSION_RUNNING: | 286 case SESSION_RUNNING: |
269 | 298 |
270 default: | 299 default: |
271 break; | 300 break; |
272 } | 301 } |
273 | 302 |
274 TRACE(("leave cli_sessionloop: fell out")) | 303 TRACE2(("leave cli_sessionloop: fell out")) |
275 | 304 |
276 } | 305 } |
277 | 306 |
278 void cli_session_cleanup() { | 307 static void cli_session_cleanup(void) { |
279 | 308 |
280 if (!sessinitdone) { | 309 if (!sessinitdone) { |
281 return; | 310 return; |
282 } | 311 } |
283 | 312 |
291 | 320 |
292 } | 321 } |
293 | 322 |
294 static void cli_finished() { | 323 static void cli_finished() { |
295 | 324 |
296 cli_session_cleanup(); | 325 session_cleanup(); |
297 common_session_cleanup(); | |
298 fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username, | 326 fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username, |
299 cli_opts.remotehost, cli_opts.remoteport); | 327 cli_opts.remotehost, cli_opts.remoteport); |
300 exit(cli_ses.retval); | 328 exit(cli_ses.retval); |
301 } | 329 } |
302 | 330 |