Mercurial > dropbear
comparison common-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 | ac2158e3e403 2f1c199b6e4b |
children | c19acba28590 |
comparison
equal
deleted
inserted
replaced
799:c344607b7341 | 801:7dcb46da72d9 |
---|---|
31 #include "dss.h" | 31 #include "dss.h" |
32 #include "ssh.h" | 32 #include "ssh.h" |
33 #include "random.h" | 33 #include "random.h" |
34 #include "kex.h" | 34 #include "kex.h" |
35 #include "channel.h" | 35 #include "channel.h" |
36 #include "atomicio.h" | |
37 #include "runopts.h" | 36 #include "runopts.h" |
38 | 37 |
39 static void checktimeouts(); | 38 static void checktimeouts(); |
40 static long select_timeout(); | 39 static long select_timeout(); |
41 static int ident_readln(int fd, char* buf, int count); | 40 static int ident_readln(int fd, char* buf, int count); |
41 static void read_session_identification(); | |
42 | 42 |
43 struct sshsession ses; /* GLOBAL */ | 43 struct sshsession ses; /* GLOBAL */ |
44 | 44 |
45 /* need to know if the session struct has been initialised, this way isn't the | 45 /* need to know if the session struct has been initialised, this way isn't the |
46 * cleanest, but works OK */ | 46 * cleanest, but works OK */ |
47 int sessinitdone = 0; /* GLOBAL */ | 47 int sessinitdone = 0; /* GLOBAL */ |
48 | 48 |
49 /* this is set when we get SIGINT or SIGTERM, the handler is in main.c */ | 49 /* this is set when we get SIGINT or SIGTERM, the handler is in main.c */ |
50 int exitflag = 0; /* GLOBAL */ | 50 int exitflag = 0; /* GLOBAL */ |
51 | 51 |
52 | |
53 | |
54 /* called only at the start of a session, set up initial state */ | 52 /* called only at the start of a session, set up initial state */ |
55 void common_session_init(int sock_in, int sock_out) { | 53 void common_session_init(int sock_in, int sock_out) { |
56 | 54 |
57 TRACE(("enter session_init")) | 55 TRACE(("enter session_init")) |
58 | 56 |
82 ses.payload = NULL; | 80 ses.payload = NULL; |
83 ses.recvseq = 0; | 81 ses.recvseq = 0; |
84 | 82 |
85 initqueue(&ses.writequeue); | 83 initqueue(&ses.writequeue); |
86 | 84 |
87 ses.requirenext = SSH_MSG_KEXINIT; | 85 ses.requirenext[0] = SSH_MSG_KEXINIT; |
88 ses.dataallowed = 1; /* we can send data until we actually | 86 ses.dataallowed = 1; /* we can send data until we actually |
89 send the SSH_MSG_KEXINIT */ | 87 send the SSH_MSG_KEXINIT */ |
90 ses.ignorenext = 0; | 88 ses.ignorenext = 0; |
91 ses.lastpacket = 0; | 89 ses.lastpacket = 0; |
92 ses.reply_queue_head = NULL; | 90 ses.reply_queue_head = NULL; |
139 timeout.tv_sec = select_timeout(); | 137 timeout.tv_sec = select_timeout(); |
140 timeout.tv_usec = 0; | 138 timeout.tv_usec = 0; |
141 FD_ZERO(&writefd); | 139 FD_ZERO(&writefd); |
142 FD_ZERO(&readfd); | 140 FD_ZERO(&readfd); |
143 dropbear_assert(ses.payload == NULL); | 141 dropbear_assert(ses.payload == NULL); |
144 if (ses.sock_in != -1) { | 142 |
143 /* during initial setup we flush out the KEXINIT packet before | |
144 * attempting to read the remote version string, which might block */ | |
145 if (ses.sock_in != -1 && (ses.remoteident || isempty(&ses.writequeue))) { | |
145 FD_SET(ses.sock_in, &readfd); | 146 FD_SET(ses.sock_in, &readfd); |
146 } | 147 } |
147 if (ses.sock_out != -1 && !isempty(&ses.writequeue)) { | 148 if (ses.sock_out != -1 && !isempty(&ses.writequeue)) { |
148 FD_SET(ses.sock_out, &writefd); | 149 FD_SET(ses.sock_out, &writefd); |
149 } | 150 } |
193 } | 194 } |
194 } | 195 } |
195 | 196 |
196 if (ses.sock_in != -1) { | 197 if (ses.sock_in != -1) { |
197 if (FD_ISSET(ses.sock_in, &readfd)) { | 198 if (FD_ISSET(ses.sock_in, &readfd)) { |
198 read_packet(); | 199 if (!ses.remoteident) { |
200 /* blocking read of the version string */ | |
201 read_session_identification(); | |
202 } else { | |
203 read_packet(); | |
204 } | |
199 } | 205 } |
200 | 206 |
201 /* Process the decrypted packet. After this, the read buffer | 207 /* Process the decrypted packet. After this, the read buffer |
202 * will be ready for a new packet */ | 208 * will be ready for a new packet */ |
203 if (ses.payload != NULL) { | 209 if (ses.payload != NULL) { |
223 | 229 |
224 /* Not reached */ | 230 /* Not reached */ |
225 } | 231 } |
226 | 232 |
227 /* clean up a session on exit */ | 233 /* clean up a session on exit */ |
228 void common_session_cleanup() { | 234 void session_cleanup() { |
229 | 235 |
230 TRACE(("enter session_cleanup")) | 236 TRACE(("enter session_cleanup")) |
231 | 237 |
232 /* we can't cleanup if we don't know the session state */ | 238 /* we can't cleanup if we don't know the session state */ |
233 if (!sessinitdone) { | 239 if (!sessinitdone) { |
234 TRACE(("leave session_cleanup: !sessinitdone")) | 240 TRACE(("leave session_cleanup: !sessinitdone")) |
235 return; | 241 return; |
236 } | 242 } |
243 | |
244 if (ses.extra_session_cleanup) { | |
245 ses.extra_session_cleanup(); | |
246 } | |
237 | 247 |
238 if (ses.session_id) { | 248 if (ses.session_id) { |
239 buf_burn(ses.session_id); | 249 buf_burn(ses.session_id); |
240 buf_free(ses.session_id); | 250 buf_free(ses.session_id); |
241 ses.session_id = NULL; | 251 ses.session_id = NULL; |
251 chancleanup(); | 261 chancleanup(); |
252 | 262 |
253 TRACE(("leave session_cleanup")) | 263 TRACE(("leave session_cleanup")) |
254 } | 264 } |
255 | 265 |
256 | 266 void send_session_identification() { |
257 void session_identification() { | 267 buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1); |
258 | 268 buf_putbytes(writebuf, LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n")); |
269 buf_putbyte(writebuf, 0x0); // packet type | |
270 buf_setpos(writebuf, 0); | |
271 enqueue(&ses.writequeue, writebuf); | |
272 } | |
273 | |
274 static void read_session_identification() { | |
259 /* max length of 255 chars */ | 275 /* max length of 255 chars */ |
260 char linebuf[256]; | 276 char linebuf[256]; |
261 int len = 0; | 277 int len = 0; |
262 char done = 0; | 278 char done = 0; |
263 int i; | 279 int i; |
264 | |
265 /* write our version string, this blocks */ | |
266 if (atomicio(write, ses.sock_out, LOCAL_IDENT "\r\n", | |
267 strlen(LOCAL_IDENT "\r\n")) == DROPBEAR_FAILURE) { | |
268 ses.remoteclosed(); | |
269 } | |
270 | |
271 /* If they send more than 50 lines, something is wrong */ | 280 /* If they send more than 50 lines, something is wrong */ |
272 for (i = 0; i < 50; i++) { | 281 for (i = 0; i < 50; i++) { |
273 len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf)); | 282 len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf)); |
274 | 283 |
275 if (len < 0 && errno != EINTR) { | 284 if (len < 0 && errno != EINTR) { |