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) {