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