Mercurial > dropbear
comparison common-channel.c @ 402:173a5f89666c channel-fix
propagate from branch 'au.asn.ucc.matt.dropbear' (head b1dd3b94e60a07a176dba2b035ac79968595990a)
to branch 'au.asn.ucc.matt.dropbear.channel-fix' (head fc77c3dea87a7c0f374e738d055f0b455495cbc3)
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sat, 03 Feb 2007 08:22:58 +0000 |
parents | a707e6148060 a7eb64b9966a |
children | 8b9aba1d5fa4 |
comparison
equal
deleted
inserted
replaced
399:a707e6148060 | 402:173a5f89666c |
---|---|
41 unsigned int recvwindow, | 41 unsigned int recvwindow, |
42 unsigned int recvmaxpacket); | 42 unsigned int recvmaxpacket); |
43 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf); | 43 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf); |
44 static void send_msg_channel_window_adjust(struct Channel *channel, | 44 static void send_msg_channel_window_adjust(struct Channel *channel, |
45 unsigned int incr); | 45 unsigned int incr); |
46 static void send_msg_channel_data(struct Channel *channel, int isextended, | 46 static void send_msg_channel_data(struct Channel *channel, int isextended); |
47 unsigned int exttype); | |
48 static void send_msg_channel_eof(struct Channel *channel); | 47 static void send_msg_channel_eof(struct Channel *channel); |
49 static void send_msg_channel_close(struct Channel *channel); | 48 static void send_msg_channel_close(struct Channel *channel); |
50 static void removechannel(struct Channel *channel); | 49 static void remove_channel(struct Channel *channel); |
51 static void deletechannel(struct Channel *channel); | 50 static void delete_channel(struct Channel *channel); |
52 static void checkinitdone(struct Channel *channel); | 51 static void check_in_progress(struct Channel *channel); |
53 static void checkclose(struct Channel *channel); | 52 static unsigned int write_pending(struct Channel * channel); |
54 | 53 static void check_close(struct Channel *channel); |
55 static void closewritefd(struct Channel * channel); | 54 static void close_chan_fd(struct Channel *channel, int fd, int how); |
56 static void closereadfd(struct Channel * channel, int fd); | |
57 static void closechanfd(struct Channel *channel, int fd, int how); | |
58 | 55 |
59 #define FD_UNINIT (-2) | 56 #define FD_UNINIT (-2) |
60 #define FD_CLOSED (-1) | 57 #define FD_CLOSED (-1) |
58 | |
59 #define ERRFD_IS_READ(channel) ((channel)->extrabuf == NULL) | |
60 #define ERRFD_IS_WRITE(channel) (!ERRFD_IS_READ(channel)) | |
61 | 61 |
62 /* Initialise all the channels */ | 62 /* Initialise all the channels */ |
63 void chaninitialise(const struct ChanType *chantypes[]) { | 63 void chaninitialise(const struct ChanType *chantypes[]) { |
64 | 64 |
65 /* may as well create space for a single channel */ | 65 /* may as well create space for a single channel */ |
83 | 83 |
84 TRACE(("enter chancleanup")) | 84 TRACE(("enter chancleanup")) |
85 for (i = 0; i < ses.chansize; i++) { | 85 for (i = 0; i < ses.chansize; i++) { |
86 if (ses.channels[i] != NULL) { | 86 if (ses.channels[i] != NULL) { |
87 TRACE(("channel %d closing", i)) | 87 TRACE(("channel %d closing", i)) |
88 removechannel(ses.channels[i]); | 88 remove_channel(ses.channels[i]); |
89 } | 89 } |
90 } | 90 } |
91 m_free(ses.channels); | 91 m_free(ses.channels); |
92 TRACE(("leave chancleanup")) | 92 TRACE(("leave chancleanup")) |
93 } | 93 } |
133 } | 133 } |
134 | 134 |
135 newchan = (struct Channel*)m_malloc(sizeof(struct Channel)); | 135 newchan = (struct Channel*)m_malloc(sizeof(struct Channel)); |
136 newchan->type = type; | 136 newchan->type = type; |
137 newchan->index = i; | 137 newchan->index = i; |
138 newchan->sentclosed = newchan->recvclosed = 0; | 138 newchan->sent_close = newchan->recv_close = 0; |
139 newchan->senteof = newchan->recveof = 0; | 139 newchan->sent_eof = newchan->recv_eof = 0; |
140 | 140 |
141 newchan->remotechan = remotechan; | 141 newchan->remotechan = remotechan; |
142 newchan->transwindow = transwindow; | 142 newchan->transwindow = transwindow; |
143 newchan->transmaxpacket = transmaxpacket; | 143 newchan->transmaxpacket = transmaxpacket; |
144 | 144 |
162 | 162 |
163 return newchan; | 163 return newchan; |
164 } | 164 } |
165 | 165 |
166 /* Returns the channel structure corresponding to the channel in the current | 166 /* Returns the channel structure corresponding to the channel in the current |
167 * data packet (ses.payload must be positioned appropriately) */ | 167 * data packet (ses.payload must be positioned appropriately). |
168 struct Channel* getchannel() { | 168 * A valid channel is always returns, it will fail fatally with an unknown |
169 * channel */ | |
170 static struct Channel* getchannel_msg(const char* kind) { | |
169 | 171 |
170 unsigned int chan; | 172 unsigned int chan; |
171 | 173 |
172 chan = buf_getint(ses.payload); | 174 chan = buf_getint(ses.payload); |
173 if (chan >= ses.chansize || ses.channels[chan] == NULL) { | 175 if (chan >= ses.chansize || ses.channels[chan] == NULL) { |
174 return NULL; | 176 if (kind) { |
177 dropbear_exit("%s for unknown channel %d", kind, chan); | |
178 } else { | |
179 dropbear_exit("Unknown channel %d", chan); | |
180 } | |
175 } | 181 } |
176 return ses.channels[chan]; | 182 return ses.channels[chan]; |
183 } | |
184 | |
185 struct Channel* getchannel() { | |
186 return getchannel_msg(NULL); | |
187 } | |
188 | |
189 /* In order to tell if a writefd is closed, we put it in the readfd FD_SET. | |
190 We then just try reading a single byte from it. It'll give EAGAIN or something | |
191 if the socket is still alive (but the FD probably shouldn't be set anyway?)*/ | |
192 static void check_closed_writefd(struct Channel* channel, int fd) { | |
193 char c; | |
194 int ret; | |
195 TRACE(("enter check_closed_writefd fd %d", fd)) | |
196 if (fd < 0) { | |
197 TRACE(("leave check_closed_writefd.")) | |
198 return; | |
199 } | |
200 | |
201 /* Read something. doing read(fd,x,0) seems to become a NOP on some platforms */ | |
202 ret = read(fd, &c, 1); | |
203 TRACE(("ret %d errno %d", ret, errno)) | |
204 if (ret > 0 || (ret < 0 && (errno == EINTR || errno == EAGAIN))) { | |
205 TRACE(("leave check_closed_writefd")) | |
206 return; | |
207 } | |
208 close_chan_fd(channel, fd, SHUT_WR); | |
209 TRACE(("leave check_closed_writefd after closing %d", fd)) | |
177 } | 210 } |
178 | 211 |
179 /* Iterate through the channels, performing IO if available */ | 212 /* Iterate through the channels, performing IO if available */ |
180 void channelio(fd_set *readfds, fd_set *writefds) { | 213 void channelio(fd_set *readfds, fd_set *writefds) { |
181 | 214 |
182 struct Channel *channel; | 215 struct Channel *channel; |
183 unsigned int i; | 216 unsigned int i; |
184 | 217 |
185 /* iterate through all the possible channels */ | 218 /* foreach channel */ |
186 for (i = 0; i < ses.chansize; i++) { | 219 for (i = 0; i < ses.chansize; i++) { |
187 | 220 |
188 channel = ses.channels[i]; | 221 channel = ses.channels[i]; |
189 if (channel == NULL) { | 222 if (channel == NULL) { |
190 /* only process in-use channels */ | 223 /* only process in-use channels */ |
191 continue; | 224 continue; |
192 } | 225 } |
193 | 226 |
194 /* read data and send it over the wire */ | 227 /* read data and send it over the wire */ |
195 if (channel->readfd >= 0 && FD_ISSET(channel->readfd, readfds)) { | 228 if (channel->readfd >= 0 && FD_ISSET(channel->readfd, readfds)) { |
196 send_msg_channel_data(channel, 0, 0); | 229 send_msg_channel_data(channel, 0); |
197 } | 230 } |
198 | 231 |
199 /* read stderr data and send it over the wire */ | 232 /* read stderr data and send it over the wire */ |
200 if (channel->extrabuf == NULL && | 233 if (ERRFD_IS_READ(channel) && |
201 channel->errfd >= 0 && FD_ISSET(channel->errfd, readfds)) { | 234 channel->errfd >= 0 && FD_ISSET(channel->errfd, readfds)) { |
202 send_msg_channel_data(channel, 1, SSH_EXTENDED_DATA_STDERR); | 235 send_msg_channel_data(channel, 1); |
203 } | 236 } |
204 | 237 |
205 /* write to program/pipe stdin */ | 238 /* write to program/pipe stdin */ |
206 if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) { | 239 if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) { |
207 if (channel->initconn) { | 240 if (channel->initconn) { |
208 checkinitdone(channel); | 241 /* XXX should this go somewhere cleaner? */ |
242 check_in_progress(channel); | |
209 continue; /* Important not to use the channel after | 243 continue; /* Important not to use the channel after |
210 checkinitdone(), as it may be NULL */ | 244 check_in_progress(), as it may be NULL */ |
211 } | 245 } |
212 writechannel(channel, channel->writefd, channel->writebuf); | 246 writechannel(channel, channel->writefd, channel->writebuf); |
213 } | 247 } |
214 | 248 |
215 /* stderr for client mode */ | 249 /* stderr for client mode */ |
216 if (channel->extrabuf != NULL | 250 if (ERRFD_IS_WRITE(channel) |
217 && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) { | 251 && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) { |
218 writechannel(channel, channel->errfd, channel->extrabuf); | 252 writechannel(channel, channel->errfd, channel->extrabuf); |
219 } | 253 } |
220 | 254 |
221 /* now handle any of the channel-closing type stuff */ | 255 /* Check writefds for close, even if we don't have anything |
222 checkclose(channel); | 256 to write into them. */ |
223 | 257 if (channel->writefd >= 0) { |
224 } /* foreach channel */ | 258 check_closed_writefd(channel, channel->writefd); |
259 } | |
260 if (ERRFD_IS_WRITE(channel) && channel->errfd >= 0) { | |
261 check_closed_writefd(channel, channel->errfd); | |
262 } | |
263 | |
264 | |
265 /* handle any channel closing etc */ | |
266 check_close(channel); | |
267 | |
268 } | |
225 | 269 |
226 /* Listeners such as TCP, X11, agent-auth */ | 270 /* Listeners such as TCP, X11, agent-auth */ |
227 #ifdef USING_LISTENERS | 271 #ifdef USING_LISTENERS |
228 handle_listeners(readfds); | 272 handle_listeners(readfds); |
229 #endif | 273 #endif |
230 } | 274 } |
231 | 275 |
232 | 276 |
233 /* do all the EOF/close type stuff checking for a channel */ | 277 /* Returns true if there is data remaining to be written to stdin or |
234 static void checkclose(struct Channel *channel) { | 278 * stderr of a channel's endpoint. */ |
235 | 279 static unsigned int write_pending(struct Channel * channel) { |
236 TRACE(("checkclose: writefd %d, readfd %d, errfd %d, sentclosed %d, recvclosed %d", | 280 |
281 if (channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0) { | |
282 return 1; | |
283 } else if (channel->errfd >= 0 && channel->extrabuf && | |
284 cbuf_getused(channel->extrabuf) > 0) { | |
285 return 1; | |
286 } | |
287 return 0; | |
288 } | |
289 | |
290 | |
291 /* EOF/close handling */ | |
292 static void check_close(struct Channel *channel) { | |
293 | |
294 TRACE(("check_close: writefd %d, readfd %d, errfd %d, sent_close %d, recv_close %d", | |
237 channel->writefd, channel->readfd, | 295 channel->writefd, channel->readfd, |
238 channel->errfd, channel->sentclosed, channel->recvclosed)) | 296 channel->errfd, channel->sent_close, channel->recv_close)) |
239 TRACE(("writebuf size %d extrabuf ptr 0x%x extrabuf size %d", | 297 TRACE(("writebuf size %d extrabuf size %d", |
240 cbuf_getused(channel->writebuf), | 298 cbuf_getused(channel->writebuf), |
241 channel->writebuf, | 299 channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0)) |
242 channel->writebuf ? 0 : cbuf_getused(channel->extrabuf))) | 300 |
243 | 301 if (channel->recv_close && !write_pending(channel)) { |
244 if (!channel->sentclosed) { | 302 if (! channel->sent_close) { |
245 | |
246 /* check for exited - currently only used for server sessions, | |
247 * if the shell has exited etc */ | |
248 if (channel->type->checkclose) { | |
249 if (channel->type->checkclose(channel)) { | |
250 closewritefd(channel); | |
251 } | |
252 } | |
253 | |
254 if (!channel->senteof | |
255 && channel->readfd == FD_CLOSED | |
256 && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) { | |
257 send_msg_channel_eof(channel); | |
258 } | |
259 | |
260 if (channel->writefd == FD_CLOSED | |
261 && channel->readfd == FD_CLOSED | |
262 && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) { | |
263 send_msg_channel_close(channel); | |
264 } | |
265 } | |
266 | |
267 /* When either party wishes to terminate the channel, it sends | |
268 * SSH_MSG_CHANNEL_CLOSE. Upon receiving this message, a party MUST | |
269 * send back a SSH_MSG_CHANNEL_CLOSE unless it has already sent this | |
270 * message for the channel. The channel is considered closed for a | |
271 * party when it has both sent and received SSH_MSG_CHANNEL_CLOSE, and | |
272 * the party may then reuse the channel number. A party MAY send | |
273 * SSH_MSG_CHANNEL_CLOSE without having sent or received | |
274 * SSH_MSG_CHANNEL_EOF. | |
275 * (from draft-ietf-secsh-connect) | |
276 */ | |
277 if (channel->recvclosed) { | |
278 if (! channel->sentclosed) { | |
279 TRACE(("Sending MSG_CHANNEL_CLOSE in response to same.")) | 303 TRACE(("Sending MSG_CHANNEL_CLOSE in response to same.")) |
280 send_msg_channel_close(channel); | 304 send_msg_channel_close(channel); |
281 } | 305 } |
282 removechannel(channel); | 306 remove_channel(channel); |
283 } | 307 return; |
308 } | |
309 | |
310 if (channel->recv_eof && !write_pending(channel)) { | |
311 close_chan_fd(channel, channel->writefd, SHUT_WR); | |
312 } | |
313 | |
314 /* If we're not going to send any more data, send EOF */ | |
315 if (!channel->sent_eof | |
316 && channel->readfd == FD_CLOSED | |
317 && (ERRFD_IS_WRITE(channel) || channel->errfd == FD_CLOSED)) { | |
318 send_msg_channel_eof(channel); | |
319 } | |
320 | |
321 /* And if we can't receive any more data from them either, close up */ | |
322 if (!channel->sent_close | |
323 && channel->writefd == FD_CLOSED | |
324 && channel->readfd == FD_CLOSED | |
325 && channel->errfd == FD_CLOSED) { | |
326 send_msg_channel_close(channel); | |
327 } | |
328 | |
284 } | 329 } |
285 | 330 |
286 | 331 |
287 /* Check whether a deferred (EINPROGRESS) connect() was successful, and | 332 /* Check whether a deferred (EINPROGRESS) connect() was successful, and |
288 * if so, set up the channel properly. Otherwise, the channel is cleaned up, so | 333 * if so, set up the channel properly. Otherwise, the channel is cleaned up, so |
289 * it is important that the channel reference isn't used after a call to this | 334 * it is important that the channel reference isn't used after a call to this |
290 * function */ | 335 * function */ |
291 static void checkinitdone(struct Channel *channel) { | 336 static void check_in_progress(struct Channel *channel) { |
292 | 337 |
293 int val; | 338 int val; |
294 socklen_t vallen = sizeof(val); | 339 socklen_t vallen = sizeof(val); |
295 | 340 |
296 TRACE(("enter checkinitdone")) | 341 TRACE(("enter check_in_progress")) |
297 | 342 |
298 if (getsockopt(channel->writefd, SOL_SOCKET, SO_ERROR, &val, &vallen) | 343 if (getsockopt(channel->writefd, SOL_SOCKET, SO_ERROR, &val, &vallen) |
299 || val != 0) { | 344 || val != 0) { |
300 send_msg_channel_open_failure(channel->remotechan, | 345 send_msg_channel_open_failure(channel->remotechan, |
301 SSH_OPEN_CONNECT_FAILED, "", ""); | 346 SSH_OPEN_CONNECT_FAILED, "", ""); |
302 close(channel->writefd); | 347 close(channel->writefd); |
303 deletechannel(channel); | 348 delete_channel(channel); |
304 TRACE(("leave checkinitdone: fail")) | 349 TRACE(("leave check_in_progress: fail")) |
305 } else { | 350 } else { |
306 send_msg_channel_open_confirmation(channel, channel->recvwindow, | 351 send_msg_channel_open_confirmation(channel, channel->recvwindow, |
307 channel->recvmaxpacket); | 352 channel->recvmaxpacket); |
308 channel->readfd = channel->writefd; | 353 channel->readfd = channel->writefd; |
309 channel->initconn = 0; | 354 channel->initconn = 0; |
310 TRACE(("leave checkinitdone: success")) | 355 TRACE(("leave check_in_progress: success")) |
311 } | 356 } |
312 } | 357 } |
313 | |
314 | 358 |
315 | 359 |
316 /* Send the close message and set the channel as closed */ | 360 /* Send the close message and set the channel as closed */ |
317 static void send_msg_channel_close(struct Channel *channel) { | 361 static void send_msg_channel_close(struct Channel *channel) { |
318 | 362 |
319 TRACE(("enter send_msg_channel_close")) | 363 TRACE(("enter send_msg_channel_close")) |
320 /* XXX server */ | |
321 if (channel->type->closehandler) { | 364 if (channel->type->closehandler) { |
322 channel->type->closehandler(channel); | 365 channel->type->closehandler(channel); |
323 } | 366 } |
324 | 367 |
325 CHECKCLEARTOWRITE(); | 368 CHECKCLEARTOWRITE(); |
327 buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_CLOSE); | 370 buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_CLOSE); |
328 buf_putint(ses.writepayload, channel->remotechan); | 371 buf_putint(ses.writepayload, channel->remotechan); |
329 | 372 |
330 encrypt_packet(); | 373 encrypt_packet(); |
331 | 374 |
332 channel->senteof = 1; | 375 channel->sent_eof = 1; |
333 channel->sentclosed = 1; | 376 channel->sent_close = 1; |
334 TRACE(("leave send_msg_channel_close")) | 377 TRACE(("leave send_msg_channel_close")) |
335 } | 378 } |
336 | 379 |
337 /* call this when trans/eof channels are closed */ | 380 /* call this when trans/eof channels are closed */ |
338 static void send_msg_channel_eof(struct Channel *channel) { | 381 static void send_msg_channel_eof(struct Channel *channel) { |
343 buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_EOF); | 386 buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_EOF); |
344 buf_putint(ses.writepayload, channel->remotechan); | 387 buf_putint(ses.writepayload, channel->remotechan); |
345 | 388 |
346 encrypt_packet(); | 389 encrypt_packet(); |
347 | 390 |
348 channel->senteof = 1; | 391 channel->sent_eof = 1; |
349 | 392 |
350 TRACE(("leave send_msg_channel_eof")) | 393 TRACE(("leave send_msg_channel_eof")) |
351 } | 394 } |
352 | 395 |
353 /* Called to write data out to the local side of the channel. | 396 /* Called to write data out to the local side of the channel. |
355 * possible */ | 398 * possible */ |
356 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) { | 399 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) { |
357 | 400 |
358 int len, maxlen; | 401 int len, maxlen; |
359 | 402 |
360 TRACE(("enter writechannel")) | 403 TRACE(("enter writechannel fd %d", fd)) |
361 | 404 |
362 maxlen = cbuf_readlen(cbuf); | 405 maxlen = cbuf_readlen(cbuf); |
363 | 406 |
364 /* Write the data out */ | 407 /* Write the data out */ |
365 len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen); | 408 len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen); |
366 if (len <= 0) { | 409 if (len <= 0) { |
410 TRACE(("errno %d len %d", errno, len)) | |
367 if (len < 0 && errno != EINTR) { | 411 if (len < 0 && errno != EINTR) { |
368 /* no more to write - we close it even if the fd was stderr, since | 412 close_chan_fd(channel, fd, SHUT_WR); |
369 * that's a nasty failure too */ | |
370 closewritefd(channel); | |
371 } | 413 } |
372 TRACE(("leave writechannel: len <= 0")) | 414 TRACE(("leave writechannel: len <= 0")) |
373 return; | 415 return; |
374 } | 416 } |
417 TRACE(("writechannel wrote %d", len)) | |
375 | 418 |
376 cbuf_incrread(cbuf, len); | 419 cbuf_incrread(cbuf, len); |
377 channel->recvdonelen += len; | 420 channel->recvdonelen += len; |
378 | |
379 if (fd == channel->writefd && cbuf_getused(cbuf) == 0 && channel->recveof) { | |
380 /* Check if we're closing up */ | |
381 closewritefd(channel); | |
382 TRACE(("leave writechannel: recveof set")) | |
383 return; | |
384 } | |
385 | 421 |
386 /* Window adjust handling */ | 422 /* Window adjust handling */ |
387 if (channel->recvdonelen >= RECV_WINDOWEXTEND) { | 423 if (channel->recvdonelen >= RECV_WINDOWEXTEND) { |
388 /* Set it back to max window */ | 424 /* Set it back to max window */ |
389 send_msg_channel_window_adjust(channel, channel->recvdonelen); | 425 send_msg_channel_window_adjust(channel, channel->recvdonelen); |
394 dropbear_assert(channel->recvwindow <= RECV_MAXWINDOW); | 430 dropbear_assert(channel->recvwindow <= RECV_MAXWINDOW); |
395 dropbear_assert(channel->recvwindow <= cbuf_getavail(channel->writebuf)); | 431 dropbear_assert(channel->recvwindow <= cbuf_getavail(channel->writebuf)); |
396 dropbear_assert(channel->extrabuf == NULL || | 432 dropbear_assert(channel->extrabuf == NULL || |
397 channel->recvwindow <= cbuf_getavail(channel->extrabuf)); | 433 channel->recvwindow <= cbuf_getavail(channel->extrabuf)); |
398 | 434 |
399 | |
400 TRACE(("leave writechannel")) | 435 TRACE(("leave writechannel")) |
401 } | 436 } |
402 | 437 |
403 /* Set the file descriptors for the main select in session.c | 438 /* Set the file descriptors for the main select in session.c |
404 * This avoid channels which don't have any window available, are closed, etc*/ | 439 * This avoid channels which don't have any window available, are closed, etc*/ |
419 | 454 |
420 if (channel->readfd >= 0) { | 455 if (channel->readfd >= 0) { |
421 FD_SET(channel->readfd, readfds); | 456 FD_SET(channel->readfd, readfds); |
422 } | 457 } |
423 | 458 |
424 if (channel->extrabuf == NULL && channel->errfd >= 0) { | 459 if (ERRFD_IS_READ(channel) && channel->errfd >= 0) { |
425 FD_SET(channel->errfd, readfds); | 460 FD_SET(channel->errfd, readfds); |
426 } | 461 } |
427 } | 462 } |
428 | 463 |
429 /* Stuff from the wire */ | 464 /* Stuff from the wire */ |
430 if ((channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0 ) | 465 if ((channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0 ) |
431 || channel->initconn) { | 466 || channel->initconn) { |
432 | |
433 FD_SET(channel->writefd, writefds); | 467 FD_SET(channel->writefd, writefds); |
434 } | 468 } |
435 | 469 |
436 if (channel->extrabuf != NULL && channel->errfd >= 0 | 470 if (ERRFD_IS_WRITE(channel) != NULL && channel->errfd >= 0 |
437 && cbuf_getused(channel->extrabuf) > 0 ) { | 471 && cbuf_getused(channel->extrabuf) > 0 ) { |
438 FD_SET(channel->errfd, writefds); | 472 FD_SET(channel->errfd, writefds); |
439 } | 473 } |
474 | |
475 /* We also set the writefds for reading, so that we will be notified of close */ | |
476 if (channel->writefd >= 0) { | |
477 FD_SET(channel->writefd, readfds); | |
478 } | |
479 if (ERRFD_IS_WRITE(channel) && channel->errfd >= 0) { | |
480 FD_SET(channel->errfd, readfds); | |
481 } | |
482 | |
483 | |
440 | 484 |
441 } /* foreach channel */ | 485 } /* foreach channel */ |
442 | 486 |
443 #ifdef USING_LISTENERS | 487 #ifdef USING_LISTENERS |
444 set_listener_fds(readfds); | 488 set_listener_fds(readfds); |
453 | 497 |
454 struct Channel * channel; | 498 struct Channel * channel; |
455 | 499 |
456 TRACE(("enter recv_msg_channel_eof")) | 500 TRACE(("enter recv_msg_channel_eof")) |
457 | 501 |
458 channel = getchannel(); | 502 channel = getchannel_msg("EOF"); |
459 if (channel == NULL) { | 503 |
460 dropbear_exit("EOF for unknown channel"); | 504 channel->recv_eof = 1; |
461 } | 505 |
462 | 506 check_close(channel); |
463 channel->recveof = 1; | |
464 if (cbuf_getused(channel->writebuf) == 0 | |
465 && (channel->extrabuf == NULL | |
466 || cbuf_getused(channel->extrabuf) == 0)) { | |
467 closewritefd(channel); | |
468 } | |
469 | |
470 TRACE(("leave recv_msg_channel_eof")) | 507 TRACE(("leave recv_msg_channel_eof")) |
471 } | 508 } |
472 | 509 |
473 | 510 |
474 /* Handle channel closure(), respond in kind and close the channels */ | 511 /* Handle channel closure(), respond in kind and close the channels */ |
476 | 513 |
477 struct Channel * channel; | 514 struct Channel * channel; |
478 | 515 |
479 TRACE(("enter recv_msg_channel_close")) | 516 TRACE(("enter recv_msg_channel_close")) |
480 | 517 |
481 channel = getchannel(); | 518 channel = getchannel_msg("Close"); |
482 if (channel == NULL) { | 519 |
483 /* disconnect ? */ | 520 channel->recv_eof = 1; |
484 dropbear_exit("Close for unknown channel"); | 521 channel->recv_close = 1; |
485 } | 522 |
486 | 523 check_close(channel); |
487 channel->recveof = 1; | |
488 channel->recvclosed = 1; | |
489 | |
490 if (channel->sentclosed) { | |
491 removechannel(channel); | |
492 } | |
493 | |
494 TRACE(("leave recv_msg_channel_close")) | 524 TRACE(("leave recv_msg_channel_close")) |
495 } | 525 } |
496 | 526 |
497 /* Remove a channel entry, this is only executed after both sides have sent | 527 /* Remove a channel entry, this is only executed after both sides have sent |
498 * channel close */ | 528 * channel close */ |
499 static void removechannel(struct Channel * channel) { | 529 static void remove_channel(struct Channel * channel) { |
500 | 530 |
501 TRACE(("enter removechannel")) | 531 TRACE(("enter remove_channel")) |
502 TRACE(("channel index is %d", channel->index)) | 532 TRACE(("channel index is %d", channel->index)) |
503 | 533 |
504 cbuf_free(channel->writebuf); | 534 cbuf_free(channel->writebuf); |
505 channel->writebuf = NULL; | 535 channel->writebuf = NULL; |
506 | 536 |
509 channel->extrabuf = NULL; | 539 channel->extrabuf = NULL; |
510 } | 540 } |
511 | 541 |
512 | 542 |
513 /* close the FDs in case they haven't been done | 543 /* close the FDs in case they haven't been done |
514 * yet (ie they were shutdown etc */ | 544 * yet (they might have been shutdown etc) */ |
545 TRACE(("CLOSE writefd %d", channel->writefd)) | |
515 close(channel->writefd); | 546 close(channel->writefd); |
547 TRACE(("CLOSE readfd %d", channel->readfd)) | |
516 close(channel->readfd); | 548 close(channel->readfd); |
549 TRACE(("CLOSE errfd %d", channel->errfd)) | |
517 close(channel->errfd); | 550 close(channel->errfd); |
518 | 551 |
519 channel->typedata = NULL; | 552 channel->typedata = NULL; |
520 | 553 |
521 deletechannel(channel); | 554 delete_channel(channel); |
522 | 555 |
523 TRACE(("leave removechannel")) | 556 TRACE(("leave remove_channel")) |
524 } | 557 } |
525 | 558 |
526 /* Remove a channel entry */ | 559 /* Remove a channel entry */ |
527 static void deletechannel(struct Channel *channel) { | 560 static void delete_channel(struct Channel *channel) { |
528 | 561 |
529 ses.channels[channel->index] = NULL; | 562 ses.channels[channel->index] = NULL; |
530 m_free(channel); | 563 m_free(channel); |
531 ses.chancount--; | 564 ses.chancount--; |
532 | 565 |
540 struct Channel *channel; | 573 struct Channel *channel; |
541 | 574 |
542 TRACE(("enter recv_msg_channel_request")) | 575 TRACE(("enter recv_msg_channel_request")) |
543 | 576 |
544 channel = getchannel(); | 577 channel = getchannel(); |
545 if (channel == NULL) { | |
546 /* disconnect ? */ | |
547 dropbear_exit("Unknown channel"); | |
548 } | |
549 | 578 |
550 if (channel->type->reqhandler) { | 579 if (channel->type->reqhandler) { |
551 channel->type->reqhandler(channel); | 580 channel->type->reqhandler(channel); |
552 } else { | 581 } else { |
553 send_msg_channel_failure(channel); | 582 send_msg_channel_failure(channel); |
560 /* Reads data from the server's program/shell/etc, and puts it in a | 589 /* Reads data from the server's program/shell/etc, and puts it in a |
561 * channel_data packet to send. | 590 * channel_data packet to send. |
562 * chan is the remote channel, isextended is 0 if it is normal data, 1 | 591 * chan is the remote channel, isextended is 0 if it is normal data, 1 |
563 * if it is extended data. if it is extended, then the type is in | 592 * if it is extended data. if it is extended, then the type is in |
564 * exttype */ | 593 * exttype */ |
565 static void send_msg_channel_data(struct Channel *channel, int isextended, | 594 static void send_msg_channel_data(struct Channel *channel, int isextended) { |
566 unsigned int exttype) { | 595 |
567 | |
568 buffer *buf; | |
569 int len; | 596 int len; |
570 unsigned int maxlen; | 597 size_t maxlen, size_pos; |
571 int fd; | 598 int fd; |
572 | 599 |
573 /* TRACE(("enter send_msg_channel_data")) | |
574 TRACE(("extended = %d type = %d", isextended, exttype))*/ | |
575 | |
576 CHECKCLEARTOWRITE(); | 600 CHECKCLEARTOWRITE(); |
577 | 601 |
578 dropbear_assert(!channel->sentclosed); | 602 dropbear_assert(!channel->sent_close); |
579 | 603 |
580 if (isextended) { | 604 if (isextended) { |
581 fd = channel->errfd; | 605 fd = channel->errfd; |
582 } else { | 606 } else { |
583 fd = channel->readfd; | 607 fd = channel->readfd; |
584 } | 608 } |
609 TRACE(("enter send_msg_channel_data isextended %d fd %d", isextended, fd)) | |
585 dropbear_assert(fd >= 0); | 610 dropbear_assert(fd >= 0); |
586 | 611 |
587 maxlen = MIN(channel->transwindow, channel->transmaxpacket); | 612 maxlen = MIN(channel->transwindow, channel->transmaxpacket); |
588 /* -(1+4+4) is SSH_MSG_CHANNEL_DATA, channel number, string length, and | 613 /* -(1+4+4) is SSH_MSG_CHANNEL_DATA, channel number, string length, and |
589 * exttype if is extended */ | 614 * exttype if is extended */ |
590 maxlen = MIN(maxlen, | 615 maxlen = MIN(maxlen, |
591 ses.writepayload->size - 1 - 4 - 4 - (isextended ? 4 : 0)); | 616 ses.writepayload->size - 1 - 4 - 4 - (isextended ? 4 : 0)); |
617 TRACE(("maxlen %d", maxlen)) | |
592 if (maxlen == 0) { | 618 if (maxlen == 0) { |
593 TRACE(("leave send_msg_channel_data: no window")) | 619 TRACE(("leave send_msg_channel_data: no window")) |
594 return; /* the data will get written later */ | |
595 } | |
596 | |
597 /* read the data */ | |
598 TRACE(("maxlen %d", maxlen)) | |
599 buf = buf_new(maxlen); | |
600 TRACE(("buf pos %d data %x", buf->pos, buf->data)) | |
601 len = read(fd, buf_getwriteptr(buf, maxlen), maxlen); | |
602 if (len <= 0) { | |
603 /* on error/eof, send eof */ | |
604 if (len == 0 || errno != EINTR) { | |
605 closereadfd(channel, fd); | |
606 } | |
607 buf_free(buf); | |
608 buf = NULL; | |
609 TRACE(("leave send_msg_channel_data: read err or EOF for fd %d", | |
610 channel->index)); | |
611 return; | 620 return; |
612 } | 621 } |
613 buf_incrlen(buf, len); | |
614 | 622 |
615 buf_putbyte(ses.writepayload, | 623 buf_putbyte(ses.writepayload, |
616 isextended ? SSH_MSG_CHANNEL_EXTENDED_DATA : SSH_MSG_CHANNEL_DATA); | 624 isextended ? SSH_MSG_CHANNEL_EXTENDED_DATA : SSH_MSG_CHANNEL_DATA); |
617 buf_putint(ses.writepayload, channel->remotechan); | 625 buf_putint(ses.writepayload, channel->remotechan); |
618 | |
619 if (isextended) { | 626 if (isextended) { |
620 buf_putint(ses.writepayload, exttype); | 627 buf_putint(ses.writepayload, SSH_EXTENDED_DATA_STDERR); |
621 } | 628 } |
622 | 629 /* a dummy size first ...*/ |
623 buf_putstring(ses.writepayload, buf_getptr(buf, len), len); | 630 size_pos = ses.writepayload->pos; |
624 buf_free(buf); | 631 buf_putint(ses.writepayload, 0); |
625 buf = NULL; | 632 |
633 /* read the data */ | |
634 len = read(fd, buf_getwriteptr(ses.writepayload, maxlen), maxlen); | |
635 if (len <= 0) { | |
636 if (len == 0 || errno != EINTR) { | |
637 close_chan_fd(channel, fd, SHUT_RD); | |
638 } | |
639 ses.writepayload->len = ses.writepayload->pos = 0; | |
640 TRACE(("leave send_msg_channel_data: len %d read err or EOF for fd %d", | |
641 len, channel->index)); | |
642 return; | |
643 } | |
644 buf_incrwritepos(ses.writepayload, len); | |
645 /* ... real size here */ | |
646 buf_setpos(ses.writepayload, size_pos); | |
647 buf_putint(ses.writepayload, len); | |
626 | 648 |
627 channel->transwindow -= len; | 649 channel->transwindow -= len; |
628 | 650 |
629 encrypt_packet(); | 651 encrypt_packet(); |
630 TRACE(("leave send_msg_channel_data")) | 652 TRACE(("leave send_msg_channel_data")) |
634 void recv_msg_channel_data() { | 656 void recv_msg_channel_data() { |
635 | 657 |
636 struct Channel *channel; | 658 struct Channel *channel; |
637 | 659 |
638 channel = getchannel(); | 660 channel = getchannel(); |
639 if (channel == NULL) { | |
640 dropbear_exit("Unknown channel"); | |
641 } | |
642 | 661 |
643 common_recv_msg_channel_data(channel, channel->writefd, channel->writebuf); | 662 common_recv_msg_channel_data(channel, channel->writefd, channel->writebuf); |
644 } | 663 } |
645 | 664 |
646 /* Shared for data and stderr data - when we receive data, put it in a buffer | 665 /* Shared for data and stderr data - when we receive data, put it in a buffer |
653 unsigned int buflen; | 672 unsigned int buflen; |
654 unsigned int len; | 673 unsigned int len; |
655 | 674 |
656 TRACE(("enter recv_msg_channel_data")) | 675 TRACE(("enter recv_msg_channel_data")) |
657 | 676 |
658 if (channel->recveof) { | 677 if (channel->recv_eof) { |
659 dropbear_exit("received data after eof"); | 678 dropbear_exit("received data after eof"); |
660 } | 679 } |
661 | 680 |
662 if (fd < 0) { | 681 if (fd < 0) { |
663 dropbear_exit("received data with bad writefd"); | 682 /* If we have encountered failed write, the far side might still |
683 * be sending data without having yet received our close notification. | |
684 * We just drop the data. */ | |
685 return; | |
664 } | 686 } |
665 | 687 |
666 datalen = buf_getint(ses.payload); | 688 datalen = buf_getint(ses.payload); |
667 | 689 TRACE(("length %d", datalen)) |
668 | 690 |
669 maxdata = cbuf_getavail(cbuf); | 691 maxdata = cbuf_getavail(cbuf); |
670 | 692 |
671 /* Whilst the spec says we "MAY ignore data past the end" this could | 693 /* Whilst the spec says we "MAY ignore data past the end" this could |
672 * lead to corrupted file transfers etc (chunks missed etc). It's better to | 694 * lead to corrupted file transfers etc (chunks missed etc). It's better to |
704 | 726 |
705 struct Channel * channel; | 727 struct Channel * channel; |
706 unsigned int incr; | 728 unsigned int incr; |
707 | 729 |
708 channel = getchannel(); | 730 channel = getchannel(); |
709 if (channel == NULL) { | |
710 dropbear_exit("Unknown channel"); | |
711 } | |
712 | 731 |
713 incr = buf_getint(ses.payload); | 732 incr = buf_getint(ses.payload); |
714 TRACE(("received window increment %d", incr)) | 733 TRACE(("received window increment %d", incr)) |
715 incr = MIN(incr, MAX_TRANS_WIN_INCR); | 734 incr = MIN(incr, MAX_TRANS_WIN_INCR); |
716 | 735 |
733 | 752 |
734 encrypt_packet(); | 753 encrypt_packet(); |
735 } | 754 } |
736 | 755 |
737 /* Handle a new channel request, performing any channel-type-specific setup */ | 756 /* Handle a new channel request, performing any channel-type-specific setup */ |
738 /* XXX server */ | |
739 void recv_msg_channel_open() { | 757 void recv_msg_channel_open() { |
740 | 758 |
741 unsigned char *type; | 759 unsigned char *type; |
742 unsigned int typelen; | 760 unsigned int typelen; |
743 unsigned int remotechan, transwindow, transmaxpacket; | 761 unsigned int remotechan, transwindow, transmaxpacket; |
790 goto failure; | 808 goto failure; |
791 } | 809 } |
792 | 810 |
793 if (channel->type->inithandler) { | 811 if (channel->type->inithandler) { |
794 ret = channel->type->inithandler(channel); | 812 ret = channel->type->inithandler(channel); |
813 if (ret == SSH_OPEN_IN_PROGRESS) { | |
814 /* We'll send the confirmation later */ | |
815 goto cleanup; | |
816 } | |
795 if (ret > 0) { | 817 if (ret > 0) { |
796 if (ret == SSH_OPEN_IN_PROGRESS) { | |
797 /* We'll send the confirmation later */ | |
798 goto cleanup; | |
799 } | |
800 errtype = ret; | 818 errtype = ret; |
801 deletechannel(channel); | 819 delete_channel(channel); |
802 TRACE(("inithandler returned failure %d", ret)) | 820 TRACE(("inithandler returned failure %d", ret)) |
803 goto failure; | 821 goto failure; |
804 } | 822 } |
805 } | 823 } |
806 | 824 |
879 buf_putint(ses.writepayload, recvmaxpacket); | 897 buf_putint(ses.writepayload, recvmaxpacket); |
880 | 898 |
881 encrypt_packet(); | 899 encrypt_packet(); |
882 TRACE(("leave send_msg_channel_open_confirmation")) | 900 TRACE(("leave send_msg_channel_open_confirmation")) |
883 } | 901 } |
902 | |
903 /* close a fd, how is SHUT_RD or SHUT_WR */ | |
904 static void close_chan_fd(struct Channel *channel, int fd, int how) { | |
905 | |
906 int closein = 0, closeout = 0; | |
907 | |
908 if (channel->type->sepfds) { | |
909 TRACE(("SHUTDOWN(%d, %d)", fd, how)) | |
910 shutdown(fd, how); | |
911 if (how == 0) { | |
912 closeout = 1; | |
913 } else { | |
914 closein = 1; | |
915 } | |
916 } else { | |
917 TRACE(("CLOSE some fd %d", fd)) | |
918 close(fd); | |
919 closein = closeout = 1; | |
920 } | |
921 | |
922 if (closeout && (fd == channel->readfd)) { | |
923 channel->readfd = FD_CLOSED; | |
924 } | |
925 if (closeout && ERRFD_IS_READ(channel) && (fd == channel->errfd)) { | |
926 channel->errfd = FD_CLOSED; | |
927 } | |
928 | |
929 if (closein && fd == channel->writefd) { | |
930 channel->writefd = FD_CLOSED; | |
931 } | |
932 if (closein && ERRFD_IS_WRITE(channel) && (fd == channel->errfd)) { | |
933 channel->errfd = FD_CLOSED; | |
934 } | |
935 | |
936 /* if we called shutdown on it and all references are gone, then we | |
937 * need to close() it to stop it lingering */ | |
938 if (channel->type->sepfds && channel->readfd == FD_CLOSED | |
939 && channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) { | |
940 TRACE(("CLOSE (finally) of %d", fd)) | |
941 close(fd); | |
942 } | |
943 } | |
944 | |
884 | 945 |
885 #if defined(USING_LISTENERS) || defined(DROPBEAR_CLIENT) | 946 #if defined(USING_LISTENERS) || defined(DROPBEAR_CLIENT) |
886 /* Create a new channel, and start the open request. This is intended | 947 /* Create a new channel, and start the open request. This is intended |
887 * for X11, agent, tcp forwarding, and should be filled with channel-specific | 948 * for X11, agent, tcp forwarding, and should be filled with channel-specific |
888 * options, with the calling function calling encrypt_packet() after | 949 * options, with the calling function calling encrypt_packet() after |
928 int ret; | 989 int ret; |
929 | 990 |
930 TRACE(("enter recv_msg_channel_open_confirmation")) | 991 TRACE(("enter recv_msg_channel_open_confirmation")) |
931 | 992 |
932 channel = getchannel(); | 993 channel = getchannel(); |
933 if (channel == NULL) { | |
934 dropbear_exit("Unknown channel"); | |
935 } | |
936 | 994 |
937 if (!channel->await_open) { | 995 if (!channel->await_open) { |
938 dropbear_exit("unexpected channel reply"); | 996 dropbear_exit("unexpected channel reply"); |
939 } | 997 } |
940 channel->await_open = 0; | 998 channel->await_open = 0; |
948 | 1006 |
949 /* Run the inithandler callback */ | 1007 /* Run the inithandler callback */ |
950 if (channel->type->inithandler) { | 1008 if (channel->type->inithandler) { |
951 ret = channel->type->inithandler(channel); | 1009 ret = channel->type->inithandler(channel); |
952 if (ret > 0) { | 1010 if (ret > 0) { |
953 removechannel(channel); | 1011 remove_channel(channel); |
954 TRACE(("inithandler returned failure %d", ret)) | 1012 TRACE(("inithandler returned failure %d", ret)) |
955 } | 1013 } |
956 } | 1014 } |
957 | 1015 |
958 | 1016 |
963 void recv_msg_channel_open_failure() { | 1021 void recv_msg_channel_open_failure() { |
964 | 1022 |
965 struct Channel * channel; | 1023 struct Channel * channel; |
966 | 1024 |
967 channel = getchannel(); | 1025 channel = getchannel(); |
968 if (channel == NULL) { | |
969 dropbear_exit("Unknown channel"); | |
970 } | |
971 | 1026 |
972 if (!channel->await_open) { | 1027 if (!channel->await_open) { |
973 dropbear_exit("unexpected channel reply"); | 1028 dropbear_exit("unexpected channel reply"); |
974 } | 1029 } |
975 channel->await_open = 0; | 1030 channel->await_open = 0; |
976 | 1031 |
977 removechannel(channel); | 1032 remove_channel(channel); |
978 } | 1033 } |
979 #endif /* USING_LISTENERS */ | 1034 #endif /* USING_LISTENERS */ |
980 | |
981 /* close a stdout/stderr fd */ | |
982 static void closereadfd(struct Channel * channel, int fd) { | |
983 | |
984 /* don't close it if it is the same as writefd, | |
985 * unless writefd is already set -1 */ | |
986 TRACE(("enter closereadfd")) | |
987 closechanfd(channel, fd, 0); | |
988 TRACE(("leave closereadfd")) | |
989 } | |
990 | |
991 /* close a stdin fd */ | |
992 static void closewritefd(struct Channel * channel) { | |
993 | |
994 TRACE(("enter closewritefd")) | |
995 closechanfd(channel, channel->writefd, 1); | |
996 TRACE(("leave closewritefd")) | |
997 } | |
998 | |
999 /* close a fd, how is 0 for stdout/stderr, 1 for stdin */ | |
1000 static void closechanfd(struct Channel *channel, int fd, int how) { | |
1001 | |
1002 int closein = 0, closeout = 0; | |
1003 | |
1004 /* XXX server */ | |
1005 if (channel->type->sepfds) { | |
1006 TRACE(("shutdown((%d), %d)", fd, how)) | |
1007 shutdown(fd, how); | |
1008 if (how == 0) { | |
1009 closeout = 1; | |
1010 } else { | |
1011 closein = 1; | |
1012 } | |
1013 } else { | |
1014 close(fd); | |
1015 closein = closeout = 1; | |
1016 } | |
1017 | |
1018 if (closeout && fd == channel->readfd) { | |
1019 channel->readfd = FD_CLOSED; | |
1020 } | |
1021 if (closeout && (channel->extrabuf == NULL) && (fd == channel->errfd)) { | |
1022 channel->errfd = FD_CLOSED; | |
1023 } | |
1024 | |
1025 if (closein && fd == channel->writefd) { | |
1026 channel->writefd = FD_CLOSED; | |
1027 } | |
1028 if (closein && (channel->extrabuf != NULL) && (fd == channel->errfd)) { | |
1029 channel->errfd = FD_CLOSED; | |
1030 } | |
1031 | |
1032 /* if we called shutdown on it and all references are gone, then we | |
1033 * need to close() it to stop it lingering */ | |
1034 if (channel->type->sepfds && channel->readfd == FD_CLOSED | |
1035 && channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) { | |
1036 close(fd); | |
1037 } | |
1038 } |