comparison common-channel.c @ 367:c046b66b76cd channel-fix

propagate from branch 'au.asn.ucc.matt.dropbear' (head 31dcd7a22983ef19d6c63248e415e71d292dd0ec) to branch 'au.asn.ucc.matt.dropbear.channel-fix' (head 7559a8cc4f6abe2338636f2aced3a395a79c172c)
author Matt Johnston <matt@ucc.asn.au>
date Thu, 12 Oct 2006 03:01:10 +0000
parents 49fcc9875045
children 8d149b812669
comparison
equal deleted inserted replaced
366:59531221b846 367:c046b66b76cd
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)
61 58
62 /* Initialise all the channels */ 59 /* Initialise all the channels */
83 80
84 TRACE(("enter chancleanup")) 81 TRACE(("enter chancleanup"))
85 for (i = 0; i < ses.chansize; i++) { 82 for (i = 0; i < ses.chansize; i++) {
86 if (ses.channels[i] != NULL) { 83 if (ses.channels[i] != NULL) {
87 TRACE(("channel %d closing", i)) 84 TRACE(("channel %d closing", i))
88 removechannel(ses.channels[i]); 85 remove_channel(ses.channels[i]);
89 } 86 }
90 } 87 }
91 m_free(ses.channels); 88 m_free(ses.channels);
92 TRACE(("leave chancleanup")) 89 TRACE(("leave chancleanup"))
93 } 90 }
133 } 130 }
134 131
135 newchan = (struct Channel*)m_malloc(sizeof(struct Channel)); 132 newchan = (struct Channel*)m_malloc(sizeof(struct Channel));
136 newchan->type = type; 133 newchan->type = type;
137 newchan->index = i; 134 newchan->index = i;
138 newchan->sentclosed = newchan->recvclosed = 0; 135 newchan->sent_close = newchan->recv_close = 0;
139 newchan->senteof = newchan->recveof = 0; 136 newchan->sent_eof = newchan->recv_eof = 0;
140 137
141 newchan->remotechan = remotechan; 138 newchan->remotechan = remotechan;
142 newchan->transwindow = transwindow; 139 newchan->transwindow = transwindow;
143 newchan->transmaxpacket = transmaxpacket; 140 newchan->transmaxpacket = transmaxpacket;
144 141
162 159
163 return newchan; 160 return newchan;
164 } 161 }
165 162
166 /* Returns the channel structure corresponding to the channel in the current 163 /* Returns the channel structure corresponding to the channel in the current
167 * data packet (ses.payload must be positioned appropriately) */ 164 * data packet (ses.payload must be positioned appropriately).
168 struct Channel* getchannel() { 165 * A valid channel is always returns, it will fail fatally with an unknown
166 * channel */
167 static struct Channel* getchannel_msg(const char* kind) {
169 168
170 unsigned int chan; 169 unsigned int chan;
171 170
172 chan = buf_getint(ses.payload); 171 chan = buf_getint(ses.payload);
173 if (chan >= ses.chansize || ses.channels[chan] == NULL) { 172 if (chan >= ses.chansize || ses.channels[chan] == NULL) {
174 return NULL; 173 if (kind) {
174 dropbear_exit("%s for unknown channel %d", kind, chan);
175 } else {
176 dropbear_exit("Unknown channel %d", chan);
177 }
175 } 178 }
176 return ses.channels[chan]; 179 return ses.channels[chan];
180 }
181
182 struct Channel* getchannel() {
183 return getchannel_msg(NULL);
177 } 184 }
178 185
179 /* Iterate through the channels, performing IO if available */ 186 /* Iterate through the channels, performing IO if available */
180 void channelio(fd_set *readfds, fd_set *writefds) { 187 void channelio(fd_set *readfds, fd_set *writefds) {
181 188
182 struct Channel *channel; 189 struct Channel *channel;
183 unsigned int i; 190 unsigned int i;
184 int ret; 191
185 192 /* foreach channel */
186 /* iterate through all the possible channels */
187 for (i = 0; i < ses.chansize; i++) { 193 for (i = 0; i < ses.chansize; i++) {
188 194
189 channel = ses.channels[i]; 195 channel = ses.channels[i];
190 if (channel == NULL) { 196 if (channel == NULL) {
191 /* only process in-use channels */ 197 /* only process in-use channels */
192 continue; 198 continue;
193 } 199 }
194 200
195 /* read data and send it over the wire */ 201 /* read data and send it over the wire */
196 if (channel->readfd >= 0 && FD_ISSET(channel->readfd, readfds)) { 202 if (channel->readfd >= 0 && FD_ISSET(channel->readfd, readfds)) {
197 send_msg_channel_data(channel, 0, 0); 203 send_msg_channel_data(channel, 0);
198 } 204 }
199 205
200 /* read stderr data and send it over the wire */ 206 /* read stderr data and send it over the wire */
201 if (channel->extrabuf == NULL && 207 if (channel->extrabuf == NULL &&
202 channel->errfd >= 0 && FD_ISSET(channel->errfd, readfds)) { 208 channel->errfd >= 0 && FD_ISSET(channel->errfd, readfds)) {
203 send_msg_channel_data(channel, 1, SSH_EXTENDED_DATA_STDERR); 209 send_msg_channel_data(channel, 1);
204 }
205
206 /* if we can read from the writefd, it might be closed, so we try to
207 * see if it has errors */
208 if (IS_DROPBEAR_SERVER && channel->writefd >= 0
209 && channel->writefd != channel->readfd
210 && FD_ISSET(channel->writefd, readfds)) {
211 if (channel->initconn) {
212 /* Handling for "in progress" connection - this is needed
213 * to avoid spinning 100% CPU when we connect to a server
214 * which doesn't send anything (tcpfwding) */
215 checkinitdone(channel);
216 continue; /* Important not to use the channel after
217 checkinitdone(), as it may be NULL */
218 }
219 ret = write(channel->writefd, NULL, 0); /* Fake write */
220 if (ret < 0 && errno != EINTR && errno != EAGAIN) {
221 closewritefd(channel);
222 }
223 } 210 }
224 211
225 /* write to program/pipe stdin */ 212 /* write to program/pipe stdin */
226 if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) { 213 if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) {
227 if (channel->initconn) { 214 if (channel->initconn) {
228 checkinitdone(channel); 215 /* XXX should this go somewhere cleaner? */
216 check_in_progress(channel);
229 continue; /* Important not to use the channel after 217 continue; /* Important not to use the channel after
230 checkinitdone(), as it may be NULL */ 218 check_in_progress(), as it may be NULL */
231 } 219 }
232 writechannel(channel, channel->writefd, channel->writebuf); 220 writechannel(channel, channel->writefd, channel->writebuf);
233 } 221 }
234 222
235 /* stderr for client mode */ 223 /* stderr for client mode */
236 if (channel->extrabuf != NULL 224 if (channel->extrabuf != NULL
237 && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) { 225 && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) {
238 writechannel(channel, channel->errfd, channel->extrabuf); 226 writechannel(channel, channel->errfd, channel->extrabuf);
239 } 227 }
240 228
241 /* now handle any of the channel-closing type stuff */ 229 /* handle any channel closing etc */
242 checkclose(channel); 230 check_close(channel);
243 231
244 } /* foreach channel */ 232 }
245 233
246 /* Listeners such as TCP, X11, agent-auth */ 234 /* Listeners such as TCP, X11, agent-auth */
247 #ifdef USING_LISTENERS 235 #ifdef USING_LISTENERS
248 handle_listeners(readfds); 236 handle_listeners(readfds);
249 #endif 237 #endif
250 } 238 }
251 239
252 240
253 /* do all the EOF/close type stuff checking for a channel */ 241 /* Returns true if there is data remaining to be written to stdin or
254 static void checkclose(struct Channel *channel) { 242 * stderr of a channel's endpoint. */
255 243 static unsigned int write_pending(struct Channel * channel) {
256 TRACE(("checkclose: writefd %d, readfd %d, errfd %d, sentclosed %d, recvclosed %d", 244
245 if (channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0) {
246 return 1;
247 } else if (channel->errfd >= 0 && channel->extrabuf &&
248 cbuf_getused(channel->writebuf) > 0) {
249 return 1;
250 }
251 return 0;
252 }
253
254
255 /* EOF/close handling */
256 static void check_close(struct Channel *channel) {
257
258 TRACE(("check_close: writefd %d, readfd %d, errfd %d, sent_close %d, recv_close %d",
257 channel->writefd, channel->readfd, 259 channel->writefd, channel->readfd,
258 channel->errfd, channel->sentclosed, channel->recvclosed)) 260 channel->errfd, channel->sent_close, channel->recv_close))
259 TRACE(("writebuf size %d extrabuf ptr 0x%x extrabuf size %d", 261 TRACE(("writebuf size %d extrabuf ptr 0x%x extrabuf size %d",
260 cbuf_getused(channel->writebuf), 262 cbuf_getused(channel->writebuf),
261 channel->writebuf, 263 channel->writebuf,
262 channel->writebuf ? 0 : cbuf_getused(channel->extrabuf))) 264 channel->writebuf ? 0 : cbuf_getused(channel->extrabuf)))
263 265
264 /* server chansession channels are special, since readfd mightn't 266 /* A bit of a hack for closing up server session channels */
265 * close in the case of "sleep 4 & echo blah" until the sleep is up */ 267 if (channel->writefd >= 0
266 if (channel->type->checkclose) { 268 && channel->type->check_close
267 if (channel->type->checkclose(channel)) { 269 && channel->type->check_close(channel)) {
268 closewritefd(channel); 270 TRACE(("channel->type->check_close got hit"))
269 closereadfd(channel, channel->readfd); 271 close_chan_fd(channel, channel->writefd, SHUT_WR);
270 closereadfd(channel, channel->errfd); 272 }
271 } 273
272 } 274 if (channel->recv_close && !write_pending(channel)) {
273 275 if (! channel->sent_close) {
274 if (!channel->senteof
275 && channel->readfd == FD_CLOSED
276 && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
277 send_msg_channel_eof(channel);
278 }
279
280 if (!channel->sentclosed
281 && channel->writefd == FD_CLOSED
282 && channel->readfd == FD_CLOSED
283 && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
284 send_msg_channel_close(channel);
285 }
286
287 /* When either party wishes to terminate the channel, it sends
288 * SSH_MSG_CHANNEL_CLOSE. Upon receiving this message, a party MUST
289 * send back a SSH_MSG_CHANNEL_CLOSE unless it has already sent this
290 * message for the channel. The channel is considered closed for a
291 * party when it has both sent and received SSH_MSG_CHANNEL_CLOSE, and
292 * the party may then reuse the channel number. A party MAY send
293 * SSH_MSG_CHANNEL_CLOSE without having sent or received
294 * SSH_MSG_CHANNEL_EOF.
295 * (from draft-ietf-secsh-connect)
296 */
297 if (channel->recvclosed) {
298 if (! channel->sentclosed) {
299 TRACE(("Sending MSG_CHANNEL_CLOSE in response to same.")) 276 TRACE(("Sending MSG_CHANNEL_CLOSE in response to same."))
300 send_msg_channel_close(channel); 277 send_msg_channel_close(channel);
301 } 278 }
302 removechannel(channel); 279 remove_channel(channel);
303 } 280 return;
281 }
282
283 if (channel->recv_eof && !write_pending(channel)) {
284 close_chan_fd(channel, channel->writefd, SHUT_WR);
285 }
286
287 if (!channel->sent_eof
288 && channel->readfd == FD_CLOSED
289 && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
290 send_msg_channel_eof(channel);
291 }
292
293 if (!channel->sent_close
294 && channel->writefd == FD_CLOSED
295 && channel->readfd == FD_CLOSED
296 && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
297 send_msg_channel_close(channel);
298 }
299
304 } 300 }
305 301
306 302
307 /* Check whether a deferred (EINPROGRESS) connect() was successful, and 303 /* Check whether a deferred (EINPROGRESS) connect() was successful, and
308 * if so, set up the channel properly. Otherwise, the channel is cleaned up, so 304 * if so, set up the channel properly. Otherwise, the channel is cleaned up, so
309 * it is important that the channel reference isn't used after a call to this 305 * it is important that the channel reference isn't used after a call to this
310 * function */ 306 * function */
311 static void checkinitdone(struct Channel *channel) { 307 static void check_in_progress(struct Channel *channel) {
312 308
313 int val; 309 int val;
314 socklen_t vallen = sizeof(val); 310 socklen_t vallen = sizeof(val);
315 311
316 TRACE(("enter checkinitdone")) 312 TRACE(("enter check_in_progress"))
317 313
318 if (getsockopt(channel->writefd, SOL_SOCKET, SO_ERROR, &val, &vallen) 314 if (getsockopt(channel->writefd, SOL_SOCKET, SO_ERROR, &val, &vallen)
319 || val != 0) { 315 || val != 0) {
320 send_msg_channel_open_failure(channel->remotechan, 316 send_msg_channel_open_failure(channel->remotechan,
321 SSH_OPEN_CONNECT_FAILED, "", ""); 317 SSH_OPEN_CONNECT_FAILED, "", "");
322 close(channel->writefd); 318 close(channel->writefd);
323 deletechannel(channel); 319 delete_channel(channel);
324 TRACE(("leave checkinitdone: fail")) 320 TRACE(("leave check_in_progress: fail"))
325 } else { 321 } else {
326 send_msg_channel_open_confirmation(channel, channel->recvwindow, 322 send_msg_channel_open_confirmation(channel, channel->recvwindow,
327 channel->recvmaxpacket); 323 channel->recvmaxpacket);
328 channel->readfd = channel->writefd; 324 channel->readfd = channel->writefd;
329 channel->initconn = 0; 325 channel->initconn = 0;
330 TRACE(("leave checkinitdone: success")) 326 TRACE(("leave check_in_progress: success"))
331 } 327 }
332 } 328 }
333
334 329
335 330
336 /* Send the close message and set the channel as closed */ 331 /* Send the close message and set the channel as closed */
337 static void send_msg_channel_close(struct Channel *channel) { 332 static void send_msg_channel_close(struct Channel *channel) {
338 333
339 TRACE(("enter send_msg_channel_close")) 334 TRACE(("enter send_msg_channel_close"))
340 /* XXX server */
341 if (channel->type->closehandler) { 335 if (channel->type->closehandler) {
342 channel->type->closehandler(channel); 336 channel->type->closehandler(channel);
343 } 337 }
344 338
345 CHECKCLEARTOWRITE(); 339 CHECKCLEARTOWRITE();
347 buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_CLOSE); 341 buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_CLOSE);
348 buf_putint(ses.writepayload, channel->remotechan); 342 buf_putint(ses.writepayload, channel->remotechan);
349 343
350 encrypt_packet(); 344 encrypt_packet();
351 345
352 channel->senteof = 1; 346 channel->sent_eof = 1;
353 channel->sentclosed = 1; 347 channel->sent_close = 1;
354 TRACE(("leave send_msg_channel_close")) 348 TRACE(("leave send_msg_channel_close"))
355 } 349 }
356 350
357 /* call this when trans/eof channels are closed */ 351 /* call this when trans/eof channels are closed */
358 static void send_msg_channel_eof(struct Channel *channel) { 352 static void send_msg_channel_eof(struct Channel *channel) {
363 buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_EOF); 357 buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_EOF);
364 buf_putint(ses.writepayload, channel->remotechan); 358 buf_putint(ses.writepayload, channel->remotechan);
365 359
366 encrypt_packet(); 360 encrypt_packet();
367 361
368 channel->senteof = 1; 362 channel->sent_eof = 1;
369 363
370 TRACE(("leave send_msg_channel_eof")) 364 TRACE(("leave send_msg_channel_eof"))
371 } 365 }
372 366
373 /* Called to write data out to the local side of the channel. 367 /* Called to write data out to the local side of the channel.
383 377
384 /* Write the data out */ 378 /* Write the data out */
385 len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen); 379 len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen);
386 if (len <= 0) { 380 if (len <= 0) {
387 if (len < 0 && errno != EINTR) { 381 if (len < 0 && errno != EINTR) {
388 /* no more to write - we close it even if the fd was stderr, since 382 close_chan_fd(channel, fd, SHUT_WR);
389 * that's a nasty failure too */
390 closewritefd(channel);
391 } 383 }
392 TRACE(("leave writechannel: len <= 0")) 384 TRACE(("leave writechannel: len <= 0"))
393 return; 385 return;
394 } 386 }
395 387
396 cbuf_incrread(cbuf, len); 388 cbuf_incrread(cbuf, len);
397 channel->recvdonelen += len; 389 channel->recvdonelen += len;
398
399 if (fd == channel->writefd && cbuf_getused(cbuf) == 0 && channel->recveof) {
400 /* Check if we're closing up */
401 closewritefd(channel);
402 TRACE(("leave writechannel: recveof set"))
403 return;
404 }
405 390
406 /* Window adjust handling */ 391 /* Window adjust handling */
407 if (channel->recvdonelen >= RECV_WINDOWEXTEND) { 392 if (channel->recvdonelen >= RECV_WINDOWEXTEND) {
408 /* Set it back to max window */ 393 /* Set it back to max window */
409 send_msg_channel_window_adjust(channel, channel->recvdonelen); 394 send_msg_channel_window_adjust(channel, channel->recvdonelen);
413 398
414 dropbear_assert(channel->recvwindow <= RECV_MAXWINDOW); 399 dropbear_assert(channel->recvwindow <= RECV_MAXWINDOW);
415 dropbear_assert(channel->recvwindow <= cbuf_getavail(channel->writebuf)); 400 dropbear_assert(channel->recvwindow <= cbuf_getavail(channel->writebuf));
416 dropbear_assert(channel->extrabuf == NULL || 401 dropbear_assert(channel->extrabuf == NULL ||
417 channel->recvwindow <= cbuf_getavail(channel->extrabuf)); 402 channel->recvwindow <= cbuf_getavail(channel->extrabuf));
418
419 403
420 TRACE(("leave writechannel")) 404 TRACE(("leave writechannel"))
421 } 405 }
422 406
423 /* Set the file descriptors for the main select in session.c 407 /* Set the file descriptors for the main select in session.c
444 if (channel->extrabuf == NULL && channel->errfd >= 0) { 428 if (channel->extrabuf == NULL && channel->errfd >= 0) {
445 FD_SET(channel->errfd, readfds); 429 FD_SET(channel->errfd, readfds);
446 } 430 }
447 } 431 }
448 432
449 TRACE(("writefd = %d, readfd %d, errfd %d, bufused %d",
450 channel->writefd, channel->readfd,
451 channel->errfd,
452 cbuf_getused(channel->writebuf) ))
453
454 /* For checking FD status (ie closure etc) - we don't actually
455 * read data from writefd. We don't want to do this for the client,
456 * since redirection to /dev/null will make it spin in the select */
457 if (IS_DROPBEAR_SERVER && channel->writefd >= 0
458 && channel->writefd != channel->readfd) {
459 FD_SET(channel->writefd, readfds);
460 }
461
462 /* Stuff from the wire */ 433 /* Stuff from the wire */
463 if ((channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0 ) 434 if ((channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0 )
464 || channel->initconn) { 435 || channel->initconn) {
465 FD_SET(channel->writefd, writefds); 436 FD_SET(channel->writefd, writefds);
466 } 437 }
485 456
486 struct Channel * channel; 457 struct Channel * channel;
487 458
488 TRACE(("enter recv_msg_channel_eof")) 459 TRACE(("enter recv_msg_channel_eof"))
489 460
490 channel = getchannel(); 461 channel = getchannel_msg("EOF");
491 if (channel == NULL) { 462
492 dropbear_exit("EOF for unknown channel"); 463 channel->recv_eof = 1;
493 } 464
494 465 check_close(channel);
495 channel->recveof = 1;
496 if (cbuf_getused(channel->writebuf) == 0
497 && (channel->extrabuf == NULL
498 || cbuf_getused(channel->extrabuf) == 0)) {
499 closewritefd(channel);
500 }
501
502 TRACE(("leave recv_msg_channel_eof")) 466 TRACE(("leave recv_msg_channel_eof"))
503 } 467 }
504 468
505 469
506 /* Handle channel closure(), respond in kind and close the channels */ 470 /* Handle channel closure(), respond in kind and close the channels */
508 472
509 struct Channel * channel; 473 struct Channel * channel;
510 474
511 TRACE(("enter recv_msg_channel_close")) 475 TRACE(("enter recv_msg_channel_close"))
512 476
513 channel = getchannel(); 477 channel = getchannel_msg("Close");
514 if (channel == NULL) { 478
515 /* disconnect ? */ 479 channel->recv_eof = 1;
516 dropbear_exit("Close for unknown channel"); 480 channel->recv_close = 1;
517 } 481
518 482 check_close(channel);
519 channel->recveof = 1;
520 channel->recvclosed = 1;
521
522 if (channel->sentclosed) {
523 removechannel(channel);
524 }
525
526 TRACE(("leave recv_msg_channel_close")) 483 TRACE(("leave recv_msg_channel_close"))
527 } 484 }
528 485
529 /* Remove a channel entry, this is only executed after both sides have sent 486 /* Remove a channel entry, this is only executed after both sides have sent
530 * channel close */ 487 * channel close */
531 static void removechannel(struct Channel * channel) { 488 static void remove_channel(struct Channel * channel) {
532 489
533 TRACE(("enter removechannel")) 490 TRACE(("enter remove_channel"))
534 TRACE(("channel index is %d", channel->index)) 491 TRACE(("channel index is %d", channel->index))
535 492
536 cbuf_free(channel->writebuf); 493 cbuf_free(channel->writebuf);
537 channel->writebuf = NULL; 494 channel->writebuf = NULL;
538 495
541 channel->extrabuf = NULL; 498 channel->extrabuf = NULL;
542 } 499 }
543 500
544 501
545 /* close the FDs in case they haven't been done 502 /* close the FDs in case they haven't been done
546 * yet (ie they were shutdown etc */ 503 * yet (they might have been shutdown etc) */
547 close(channel->writefd); 504 close(channel->writefd);
548 close(channel->readfd); 505 close(channel->readfd);
549 close(channel->errfd); 506 close(channel->errfd);
550 507
551 channel->typedata = NULL; 508 channel->typedata = NULL;
552 509
553 deletechannel(channel); 510 delete_channel(channel);
554 511
555 TRACE(("leave removechannel")) 512 TRACE(("leave remove_channel"))
556 } 513 }
557 514
558 /* Remove a channel entry */ 515 /* Remove a channel entry */
559 static void deletechannel(struct Channel *channel) { 516 static void delete_channel(struct Channel *channel) {
560 517
561 ses.channels[channel->index] = NULL; 518 ses.channels[channel->index] = NULL;
562 m_free(channel); 519 m_free(channel);
563 ses.chancount--; 520 ses.chancount--;
564 521
572 struct Channel *channel; 529 struct Channel *channel;
573 530
574 TRACE(("enter recv_msg_channel_request")) 531 TRACE(("enter recv_msg_channel_request"))
575 532
576 channel = getchannel(); 533 channel = getchannel();
577 if (channel == NULL) {
578 /* disconnect ? */
579 dropbear_exit("Unknown channel");
580 }
581 534
582 if (channel->type->reqhandler) { 535 if (channel->type->reqhandler) {
583 channel->type->reqhandler(channel); 536 channel->type->reqhandler(channel);
584 } else { 537 } else {
585 send_msg_channel_failure(channel); 538 send_msg_channel_failure(channel);
592 /* Reads data from the server's program/shell/etc, and puts it in a 545 /* Reads data from the server's program/shell/etc, and puts it in a
593 * channel_data packet to send. 546 * channel_data packet to send.
594 * chan is the remote channel, isextended is 0 if it is normal data, 1 547 * chan is the remote channel, isextended is 0 if it is normal data, 1
595 * if it is extended data. if it is extended, then the type is in 548 * if it is extended data. if it is extended, then the type is in
596 * exttype */ 549 * exttype */
597 static void send_msg_channel_data(struct Channel *channel, int isextended, 550 static void send_msg_channel_data(struct Channel *channel, int isextended) {
598 unsigned int exttype) { 551
599
600 buffer *buf;
601 int len; 552 int len;
602 unsigned int maxlen; 553 size_t maxlen, size_pos;
603 int fd; 554 int fd;
604 555
605 /* TRACE(("enter send_msg_channel_data"))
606 TRACE(("extended = %d type = %d", isextended, exttype))*/
607
608 CHECKCLEARTOWRITE(); 556 CHECKCLEARTOWRITE();
609 557
610 dropbear_assert(!channel->sentclosed); 558 dropbear_assert(!channel->sent_close);
611 559
612 if (isextended) { 560 if (isextended) {
613 fd = channel->errfd; 561 fd = channel->errfd;
614 } else { 562 } else {
615 fd = channel->readfd; 563 fd = channel->readfd;
619 maxlen = MIN(channel->transwindow, channel->transmaxpacket); 567 maxlen = MIN(channel->transwindow, channel->transmaxpacket);
620 /* -(1+4+4) is SSH_MSG_CHANNEL_DATA, channel number, string length, and 568 /* -(1+4+4) is SSH_MSG_CHANNEL_DATA, channel number, string length, and
621 * exttype if is extended */ 569 * exttype if is extended */
622 maxlen = MIN(maxlen, 570 maxlen = MIN(maxlen,
623 ses.writepayload->size - 1 - 4 - 4 - (isextended ? 4 : 0)); 571 ses.writepayload->size - 1 - 4 - 4 - (isextended ? 4 : 0));
572 TRACE(("maxlen %d", maxlen))
624 if (maxlen == 0) { 573 if (maxlen == 0) {
625 TRACE(("leave send_msg_channel_data: no window")) 574 TRACE(("leave send_msg_channel_data: no window"))
626 return; /* the data will get written later */ 575 return;
627 } 576 }
577
578 buf_putbyte(ses.writepayload,
579 isextended ? SSH_MSG_CHANNEL_EXTENDED_DATA : SSH_MSG_CHANNEL_DATA);
580 buf_putint(ses.writepayload, channel->remotechan);
581 if (isextended) {
582 buf_putint(ses.writepayload, SSH_EXTENDED_DATA_STDERR);
583 }
584 /* a dummy size first ...*/
585 size_pos = ses.writepayload->pos;
586 buf_putint(ses.writepayload, 0);
628 587
629 /* read the data */ 588 /* read the data */
630 TRACE(("maxlen %d", maxlen)) 589 len = read(fd, buf_getwriteptr(ses.writepayload, maxlen), maxlen);
631 buf = buf_new(maxlen);
632 TRACE(("buf pos %d data %x", buf->pos, buf->data))
633 len = read(fd, buf_getwriteptr(buf, maxlen), maxlen);
634 if (len <= 0) { 590 if (len <= 0) {
635 /* on error/eof, send eof */
636 if (len == 0 || errno != EINTR) { 591 if (len == 0 || errno != EINTR) {
637 closereadfd(channel, fd); 592 close_chan_fd(channel, fd, SHUT_RD);
638 } 593 }
639 buf_free(buf); 594 ses.writepayload->len = ses.writepayload->pos = 0;
640 buf = NULL;
641 TRACE(("leave send_msg_channel_data: read err or EOF for fd %d", 595 TRACE(("leave send_msg_channel_data: read err or EOF for fd %d",
642 channel->index)); 596 channel->index));
643 return; 597 return;
644 } 598 }
645 buf_incrlen(buf, len); 599 buf_incrwritepos(ses.writepayload, len);
646 600 /* ... real size here */
647 buf_putbyte(ses.writepayload, 601 buf_setpos(ses.writepayload, size_pos);
648 isextended ? SSH_MSG_CHANNEL_EXTENDED_DATA : SSH_MSG_CHANNEL_DATA); 602 buf_putint(ses.writepayload, len);
649 buf_putint(ses.writepayload, channel->remotechan);
650
651 if (isextended) {
652 buf_putint(ses.writepayload, exttype);
653 }
654
655 buf_putstring(ses.writepayload, buf_getptr(buf, len), len);
656 buf_free(buf);
657 buf = NULL;
658 603
659 channel->transwindow -= len; 604 channel->transwindow -= len;
660 605
661 encrypt_packet(); 606 encrypt_packet();
662 TRACE(("leave send_msg_channel_data")) 607 TRACE(("leave send_msg_channel_data"))
666 void recv_msg_channel_data() { 611 void recv_msg_channel_data() {
667 612
668 struct Channel *channel; 613 struct Channel *channel;
669 614
670 channel = getchannel(); 615 channel = getchannel();
671 if (channel == NULL) {
672 dropbear_exit("Unknown channel");
673 }
674 616
675 common_recv_msg_channel_data(channel, channel->writefd, channel->writebuf); 617 common_recv_msg_channel_data(channel, channel->writefd, channel->writebuf);
676 } 618 }
677 619
678 /* Shared for data and stderr data - when we receive data, put it in a buffer 620 /* Shared for data and stderr data - when we receive data, put it in a buffer
685 unsigned int buflen; 627 unsigned int buflen;
686 unsigned int len; 628 unsigned int len;
687 629
688 TRACE(("enter recv_msg_channel_data")) 630 TRACE(("enter recv_msg_channel_data"))
689 631
690 if (channel->recveof) { 632 if (channel->recv_eof) {
691 dropbear_exit("received data after eof"); 633 dropbear_exit("received data after eof");
692 } 634 }
693 635
694 if (fd < 0) { 636 if (fd < 0) {
695 dropbear_exit("received data with bad writefd"); 637 /* If we have encountered failed write, the far side might still
638 * be sending data without having yet received our close notification.
639 * We just drop the data. */
640 return;
696 } 641 }
697 642
698 datalen = buf_getint(ses.payload); 643 datalen = buf_getint(ses.payload);
699 644 TRACE(("length %d", datalen))
700 645
701 maxdata = cbuf_getavail(cbuf); 646 maxdata = cbuf_getavail(cbuf);
702 647
703 /* Whilst the spec says we "MAY ignore data past the end" this could 648 /* Whilst the spec says we "MAY ignore data past the end" this could
704 * lead to corrupted file transfers etc (chunks missed etc). It's better to 649 * lead to corrupted file transfers etc (chunks missed etc). It's better to
736 681
737 struct Channel * channel; 682 struct Channel * channel;
738 unsigned int incr; 683 unsigned int incr;
739 684
740 channel = getchannel(); 685 channel = getchannel();
741 if (channel == NULL) {
742 dropbear_exit("Unknown channel");
743 }
744 686
745 incr = buf_getint(ses.payload); 687 incr = buf_getint(ses.payload);
746 TRACE(("received window increment %d", incr)) 688 TRACE(("received window increment %d", incr))
747 incr = MIN(incr, MAX_TRANS_WIN_INCR); 689 incr = MIN(incr, MAX_TRANS_WIN_INCR);
748 690
765 707
766 encrypt_packet(); 708 encrypt_packet();
767 } 709 }
768 710
769 /* Handle a new channel request, performing any channel-type-specific setup */ 711 /* Handle a new channel request, performing any channel-type-specific setup */
770 /* XXX server */
771 void recv_msg_channel_open() { 712 void recv_msg_channel_open() {
772 713
773 unsigned char *type; 714 unsigned char *type;
774 unsigned int typelen; 715 unsigned int typelen;
775 unsigned int remotechan, transwindow, transmaxpacket; 716 unsigned int remotechan, transwindow, transmaxpacket;
797 } 738 }
798 739
799 /* Get the channel type. Client and server style invokation will set up a 740 /* Get the channel type. Client and server style invokation will set up a
800 * different list for ses.chantypes at startup. We just iterate through 741 * different list for ses.chantypes at startup. We just iterate through
801 * this list and find the matching name */ 742 * this list and find the matching name */
743 /* XXX fugly */
802 for (cp = &ses.chantypes[0], chantype = (*cp); 744 for (cp = &ses.chantypes[0], chantype = (*cp);
803 chantype != NULL; 745 chantype != NULL;
804 cp++, chantype = (*cp)) { 746 cp++, chantype = (*cp)) {
805 if (strcmp(type, chantype->name) == 0) { 747 if (strcmp(type, chantype->name) == 0) {
806 break; 748 break;
822 goto failure; 764 goto failure;
823 } 765 }
824 766
825 if (channel->type->inithandler) { 767 if (channel->type->inithandler) {
826 ret = channel->type->inithandler(channel); 768 ret = channel->type->inithandler(channel);
769 if (ret == SSH_OPEN_IN_PROGRESS) {
770 /* We'll send the confirmation later */
771 goto cleanup;
772 }
827 if (ret > 0) { 773 if (ret > 0) {
828 if (ret == SSH_OPEN_IN_PROGRESS) {
829 /* We'll send the confirmation later */
830 goto cleanup;
831 }
832 errtype = ret; 774 errtype = ret;
833 deletechannel(channel); 775 delete_channel(channel);
834 TRACE(("inithandler returned failure %d", ret)) 776 TRACE(("inithandler returned failure %d", ret))
835 goto failure; 777 goto failure;
836 } 778 }
837 } 779 }
838 780
911 buf_putint(ses.writepayload, recvmaxpacket); 853 buf_putint(ses.writepayload, recvmaxpacket);
912 854
913 encrypt_packet(); 855 encrypt_packet();
914 TRACE(("leave send_msg_channel_open_confirmation")) 856 TRACE(("leave send_msg_channel_open_confirmation"))
915 } 857 }
858
859 /* close a fd, how is SHUT_RD or SHUT_WR */
860 static void close_chan_fd(struct Channel *channel, int fd, int how) {
861
862 int closein = 0, closeout = 0;
863
864 if (channel->type->sepfds) {
865 TRACE(("shutdown((%d), %d)", fd, how))
866 shutdown(fd, how);
867 if (how == 0) {
868 closeout = 1;
869 } else {
870 closein = 1;
871 }
872 } else {
873 close(fd);
874 closein = closeout = 1;
875 }
876
877 if (closeout && fd == channel->readfd) {
878 channel->readfd = FD_CLOSED;
879 }
880 if (closeout && (channel->extrabuf == NULL) && (fd == channel->errfd)) {
881 channel->errfd = FD_CLOSED;
882 }
883
884 if (closein && fd == channel->writefd) {
885 channel->writefd = FD_CLOSED;
886 }
887 if (closein && (channel->extrabuf != NULL) && (fd == channel->errfd)) {
888 channel->errfd = FD_CLOSED;
889 }
890
891 /* if we called shutdown on it and all references are gone, then we
892 * need to close() it to stop it lingering */
893 if (channel->type->sepfds && channel->readfd == FD_CLOSED
894 && channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) {
895 close(fd);
896 }
897 }
898
916 899
917 #if defined(USING_LISTENERS) || defined(DROPBEAR_CLIENT) 900 #if defined(USING_LISTENERS) || defined(DROPBEAR_CLIENT)
918 /* Create a new channel, and start the open request. This is intended 901 /* Create a new channel, and start the open request. This is intended
919 * for X11, agent, tcp forwarding, and should be filled with channel-specific 902 * for X11, agent, tcp forwarding, and should be filled with channel-specific
920 * options, with the calling function calling encrypt_packet() after 903 * options, with the calling function calling encrypt_packet() after
960 int ret; 943 int ret;
961 944
962 TRACE(("enter recv_msg_channel_open_confirmation")) 945 TRACE(("enter recv_msg_channel_open_confirmation"))
963 946
964 channel = getchannel(); 947 channel = getchannel();
965 if (channel == NULL) {
966 dropbear_exit("Unknown channel");
967 }
968 948
969 if (!channel->await_open) { 949 if (!channel->await_open) {
970 dropbear_exit("unexpected channel reply"); 950 dropbear_exit("unexpected channel reply");
971 } 951 }
972 channel->await_open = 0; 952 channel->await_open = 0;
980 960
981 /* Run the inithandler callback */ 961 /* Run the inithandler callback */
982 if (channel->type->inithandler) { 962 if (channel->type->inithandler) {
983 ret = channel->type->inithandler(channel); 963 ret = channel->type->inithandler(channel);
984 if (ret > 0) { 964 if (ret > 0) {
985 removechannel(channel); 965 remove_channel(channel);
986 TRACE(("inithandler returned failure %d", ret)) 966 TRACE(("inithandler returned failure %d", ret))
987 } 967 }
988 } 968 }
989 969
990 970
995 void recv_msg_channel_open_failure() { 975 void recv_msg_channel_open_failure() {
996 976
997 struct Channel * channel; 977 struct Channel * channel;
998 978
999 channel = getchannel(); 979 channel = getchannel();
1000 if (channel == NULL) {
1001 dropbear_exit("Unknown channel");
1002 }
1003 980
1004 if (!channel->await_open) { 981 if (!channel->await_open) {
1005 dropbear_exit("unexpected channel reply"); 982 dropbear_exit("unexpected channel reply");
1006 } 983 }
1007 channel->await_open = 0; 984 channel->await_open = 0;
1008 985
1009 removechannel(channel); 986 remove_channel(channel);
1010 } 987 }
1011 #endif /* USING_LISTENERS */ 988 #endif /* USING_LISTENERS */
1012
1013 /* close a stdout/stderr fd */
1014 static void closereadfd(struct Channel * channel, int fd) {
1015
1016 /* don't close it if it is the same as writefd,
1017 * unless writefd is already set -1 */
1018 TRACE(("enter closereadfd"))
1019 closechanfd(channel, fd, 0);
1020 TRACE(("leave closereadfd"))
1021 }
1022
1023 /* close a stdin fd */
1024 static void closewritefd(struct Channel * channel) {
1025
1026 TRACE(("enter closewritefd"))
1027 closechanfd(channel, channel->writefd, 1);
1028 TRACE(("leave closewritefd"))
1029 }
1030
1031 /* close a fd, how is 0 for stdout/stderr, 1 for stdin */
1032 static void closechanfd(struct Channel *channel, int fd, int how) {
1033
1034 int closein = 0, closeout = 0;
1035
1036 /* XXX server */
1037 if (channel->type->sepfds) {
1038 TRACE(("shutdown((%d), %d)", fd, how))
1039 shutdown(fd, how);
1040 if (how == 0) {
1041 closeout = 1;
1042 } else {
1043 closein = 1;
1044 }
1045 } else {
1046 close(fd);
1047 closein = closeout = 1;
1048 }
1049
1050 if (closeout && fd == channel->readfd) {
1051 channel->readfd = FD_CLOSED;
1052 }
1053 if (closeout && (channel->extrabuf == NULL) && (fd == channel->errfd)) {
1054 channel->errfd = FD_CLOSED;
1055 }
1056
1057 if (closein && fd == channel->writefd) {
1058 channel->writefd = FD_CLOSED;
1059 }
1060 if (closein && (channel->extrabuf != NULL) && (fd == channel->errfd)) {
1061 channel->errfd = FD_CLOSED;
1062 }
1063
1064 /* if we called shutdown on it and all references are gone, then we
1065 * need to close() it to stop it lingering */
1066 if (channel->type->sepfds && channel->readfd == FD_CLOSED
1067 && channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) {
1068 close(fd);
1069 }
1070 }