diff options
author | Colin Watson <cjwatson@debian.org> | 2016-12-20 00:22:52 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2016-12-20 00:22:52 +0000 |
commit | 971a7653746a6972b907dfe0ce139c06e4a6f482 (patch) | |
tree | 70fb964265d57ae4967be55b75dbb2a122e9b969 /serverloop.c | |
parent | a8ed8d256b2e2c05b0c15565a7938028c5192277 (diff) | |
parent | 4a354fc231174901f2629437c2a6e924a2dd6772 (diff) |
Import openssh_7.4p1.orig.tar.gz
Diffstat (limited to 'serverloop.c')
-rw-r--r-- | serverloop.c | 617 |
1 files changed, 33 insertions, 584 deletions
diff --git a/serverloop.c b/serverloop.c index 3563e5d42..c4e4699da 100644 --- a/serverloop.c +++ b/serverloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: serverloop.c,v 1.184 2016/03/07 19:02:43 djm Exp $ */ | 1 | /* $OpenBSD: serverloop.c,v 1.189 2016/12/14 00:36:34 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -37,7 +37,6 @@ | |||
37 | 37 | ||
38 | #include "includes.h" | 38 | #include "includes.h" |
39 | 39 | ||
40 | #include <sys/param.h> /* MIN MAX */ | ||
41 | #include <sys/types.h> | 40 | #include <sys/types.h> |
42 | #include <sys/wait.h> | 41 | #include <sys/wait.h> |
43 | #include <sys/socket.h> | 42 | #include <sys/socket.h> |
@@ -67,7 +66,6 @@ | |||
67 | #include "sshpty.h" | 66 | #include "sshpty.h" |
68 | #include "channels.h" | 67 | #include "channels.h" |
69 | #include "compat.h" | 68 | #include "compat.h" |
70 | #include "ssh1.h" | ||
71 | #include "ssh2.h" | 69 | #include "ssh2.h" |
72 | #include "key.h" | 70 | #include "key.h" |
73 | #include "cipher.h" | 71 | #include "cipher.h" |
@@ -86,25 +84,6 @@ extern ServerOptions options; | |||
86 | extern Authctxt *the_authctxt; | 84 | extern Authctxt *the_authctxt; |
87 | extern int use_privsep; | 85 | extern int use_privsep; |
88 | 86 | ||
89 | static Buffer stdin_buffer; /* Buffer for stdin data. */ | ||
90 | static Buffer stdout_buffer; /* Buffer for stdout data. */ | ||
91 | static Buffer stderr_buffer; /* Buffer for stderr data. */ | ||
92 | static int fdin; /* Descriptor for stdin (for writing) */ | ||
93 | static int fdout; /* Descriptor for stdout (for reading); | ||
94 | May be same number as fdin. */ | ||
95 | static int fderr; /* Descriptor for stderr. May be -1. */ | ||
96 | static long stdin_bytes = 0; /* Number of bytes written to stdin. */ | ||
97 | static long stdout_bytes = 0; /* Number of stdout bytes sent to client. */ | ||
98 | static long stderr_bytes = 0; /* Number of stderr bytes sent to client. */ | ||
99 | static long fdout_bytes = 0; /* Number of stdout bytes read from program. */ | ||
100 | static int stdin_eof = 0; /* EOF message received from client. */ | ||
101 | static int fdout_eof = 0; /* EOF encountered reading from fdout. */ | ||
102 | static int fderr_eof = 0; /* EOF encountered readung from fderr. */ | ||
103 | static int fdin_is_tty = 0; /* fdin points to a tty. */ | ||
104 | static int connection_in; /* Connection to client (input). */ | ||
105 | static int connection_out; /* Connection to client (output). */ | ||
106 | static int connection_closed = 0; /* Connection to client closed. */ | ||
107 | static u_int buffer_high; /* "Soft" max buffer size. */ | ||
108 | static int no_more_sessions = 0; /* Disallow further sessions. */ | 87 | static int no_more_sessions = 0; /* Disallow further sessions. */ |
109 | 88 | ||
110 | /* | 89 | /* |
@@ -185,64 +164,6 @@ sigterm_handler(int sig) | |||
185 | received_sigterm = sig; | 164 | received_sigterm = sig; |
186 | } | 165 | } |
187 | 166 | ||
188 | /* | ||
189 | * Make packets from buffered stderr data, and buffer it for sending | ||
190 | * to the client. | ||
191 | */ | ||
192 | static void | ||
193 | make_packets_from_stderr_data(void) | ||
194 | { | ||
195 | u_int len; | ||
196 | |||
197 | /* Send buffered stderr data to the client. */ | ||
198 | while (buffer_len(&stderr_buffer) > 0 && | ||
199 | packet_not_very_much_data_to_write()) { | ||
200 | len = buffer_len(&stderr_buffer); | ||
201 | if (packet_is_interactive()) { | ||
202 | if (len > 512) | ||
203 | len = 512; | ||
204 | } else { | ||
205 | /* Keep the packets at reasonable size. */ | ||
206 | if (len > packet_get_maxsize()) | ||
207 | len = packet_get_maxsize(); | ||
208 | } | ||
209 | packet_start(SSH_SMSG_STDERR_DATA); | ||
210 | packet_put_string(buffer_ptr(&stderr_buffer), len); | ||
211 | packet_send(); | ||
212 | buffer_consume(&stderr_buffer, len); | ||
213 | stderr_bytes += len; | ||
214 | } | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * Make packets from buffered stdout data, and buffer it for sending to the | ||
219 | * client. | ||
220 | */ | ||
221 | static void | ||
222 | make_packets_from_stdout_data(void) | ||
223 | { | ||
224 | u_int len; | ||
225 | |||
226 | /* Send buffered stdout data to the client. */ | ||
227 | while (buffer_len(&stdout_buffer) > 0 && | ||
228 | packet_not_very_much_data_to_write()) { | ||
229 | len = buffer_len(&stdout_buffer); | ||
230 | if (packet_is_interactive()) { | ||
231 | if (len > 512) | ||
232 | len = 512; | ||
233 | } else { | ||
234 | /* Keep the packets at reasonable size. */ | ||
235 | if (len > packet_get_maxsize()) | ||
236 | len = packet_get_maxsize(); | ||
237 | } | ||
238 | packet_start(SSH_SMSG_STDOUT_DATA); | ||
239 | packet_put_string(buffer_ptr(&stdout_buffer), len); | ||
240 | packet_send(); | ||
241 | buffer_consume(&stdout_buffer, len); | ||
242 | stdout_bytes += len; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | static void | 167 | static void |
247 | client_alive_check(void) | 168 | client_alive_check(void) |
248 | { | 169 | { |
@@ -275,14 +196,14 @@ client_alive_check(void) | |||
275 | * for the duration of the wait (0 = infinite). | 196 | * for the duration of the wait (0 = infinite). |
276 | */ | 197 | */ |
277 | static void | 198 | static void |
278 | wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | 199 | wait_until_can_do_something(int connection_in, int connection_out, |
200 | fd_set **readsetp, fd_set **writesetp, int *maxfdp, | ||
279 | u_int *nallocp, u_int64_t max_time_ms) | 201 | u_int *nallocp, u_int64_t max_time_ms) |
280 | { | 202 | { |
281 | struct timeval tv, *tvp; | 203 | struct timeval tv, *tvp; |
282 | int ret; | 204 | int ret; |
283 | time_t minwait_secs = 0; | 205 | time_t minwait_secs = 0; |
284 | int client_alive_scheduled = 0; | 206 | int client_alive_scheduled = 0; |
285 | int program_alive_scheduled = 0; | ||
286 | 207 | ||
287 | /* Allocate and update select() masks for channel descriptors. */ | 208 | /* Allocate and update select() masks for channel descriptors. */ |
288 | channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, | 209 | channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, |
@@ -290,7 +211,7 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | |||
290 | 211 | ||
291 | /* XXX need proper deadline system for rekey/client alive */ | 212 | /* XXX need proper deadline system for rekey/client alive */ |
292 | if (minwait_secs != 0) | 213 | if (minwait_secs != 0) |
293 | max_time_ms = MIN(max_time_ms, (u_int)minwait_secs * 1000); | 214 | max_time_ms = MINIMUM(max_time_ms, (u_int)minwait_secs * 1000); |
294 | 215 | ||
295 | /* | 216 | /* |
296 | * if using client_alive, set the max timeout accordingly, | 217 | * if using client_alive, set the max timeout accordingly, |
@@ -300,7 +221,7 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | |||
300 | * this could be randomized somewhat to make traffic | 221 | * this could be randomized somewhat to make traffic |
301 | * analysis more difficult, but we're not doing it yet. | 222 | * analysis more difficult, but we're not doing it yet. |
302 | */ | 223 | */ |
303 | if (compat20 && options.client_alive_interval) { | 224 | if (options.client_alive_interval) { |
304 | uint64_t keepalive_ms = | 225 | uint64_t keepalive_ms = |
305 | (uint64_t)options.client_alive_interval * 1000; | 226 | (uint64_t)options.client_alive_interval * 1000; |
306 | 227 | ||
@@ -309,38 +230,11 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | |||
309 | max_time_ms = keepalive_ms; | 230 | max_time_ms = keepalive_ms; |
310 | } | 231 | } |
311 | 232 | ||
312 | if (compat20) { | ||
313 | #if 0 | 233 | #if 0 |
314 | /* wrong: bad condition XXX */ | 234 | /* wrong: bad condition XXX */ |
315 | if (channel_not_very_much_buffered_data()) | 235 | if (channel_not_very_much_buffered_data()) |
316 | #endif | 236 | #endif |
317 | FD_SET(connection_in, *readsetp); | 237 | FD_SET(connection_in, *readsetp); |
318 | } else { | ||
319 | /* | ||
320 | * Read packets from the client unless we have too much | ||
321 | * buffered stdin or channel data. | ||
322 | */ | ||
323 | if (buffer_len(&stdin_buffer) < buffer_high && | ||
324 | channel_not_very_much_buffered_data()) | ||
325 | FD_SET(connection_in, *readsetp); | ||
326 | /* | ||
327 | * If there is not too much data already buffered going to | ||
328 | * the client, try to get some more data from the program. | ||
329 | */ | ||
330 | if (packet_not_very_much_data_to_write()) { | ||
331 | program_alive_scheduled = child_terminated; | ||
332 | if (!fdout_eof) | ||
333 | FD_SET(fdout, *readsetp); | ||
334 | if (!fderr_eof) | ||
335 | FD_SET(fderr, *readsetp); | ||
336 | } | ||
337 | /* | ||
338 | * If we have buffered data, try to write some of that data | ||
339 | * to the program. | ||
340 | */ | ||
341 | if (fdin != -1 && buffer_len(&stdin_buffer) > 0) | ||
342 | FD_SET(fdin, *writesetp); | ||
343 | } | ||
344 | notify_prepare(*readsetp); | 238 | notify_prepare(*readsetp); |
345 | 239 | ||
346 | /* | 240 | /* |
@@ -374,16 +268,8 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | |||
374 | memset(*writesetp, 0, *nallocp); | 268 | memset(*writesetp, 0, *nallocp); |
375 | if (errno != EINTR) | 269 | if (errno != EINTR) |
376 | error("select: %.100s", strerror(errno)); | 270 | error("select: %.100s", strerror(errno)); |
377 | } else { | 271 | } else if (ret == 0 && client_alive_scheduled) |
378 | if (ret == 0 && client_alive_scheduled) | 272 | client_alive_check(); |
379 | client_alive_check(); | ||
380 | if (!compat20 && program_alive_scheduled && fdin_is_tty) { | ||
381 | if (!fdout_eof) | ||
382 | FD_SET(fdout, *readsetp); | ||
383 | if (!fderr_eof) | ||
384 | FD_SET(fderr, *readsetp); | ||
385 | } | ||
386 | } | ||
387 | 273 | ||
388 | notify_done(*readsetp); | 274 | notify_done(*readsetp); |
389 | } | 275 | } |
@@ -392,8 +278,8 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | |||
392 | * Processes input from the client and the program. Input data is stored | 278 | * Processes input from the client and the program. Input data is stored |
393 | * in buffers and processed later. | 279 | * in buffers and processed later. |
394 | */ | 280 | */ |
395 | static void | 281 | static int |
396 | process_input(fd_set *readset) | 282 | process_input(fd_set *readset, int connection_in) |
397 | { | 283 | { |
398 | struct ssh *ssh = active_state; /* XXX */ | 284 | struct ssh *ssh = active_state; /* XXX */ |
399 | int len; | 285 | int len; |
@@ -405,10 +291,7 @@ process_input(fd_set *readset) | |||
405 | if (len == 0) { | 291 | if (len == 0) { |
406 | verbose("Connection closed by %.100s port %d", | 292 | verbose("Connection closed by %.100s port %d", |
407 | ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); | 293 | ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); |
408 | connection_closed = 1; | 294 | return -1; |
409 | if (compat20) | ||
410 | return; | ||
411 | cleanup_exit(255); | ||
412 | } else if (len < 0) { | 295 | } else if (len < 0) { |
413 | if (errno != EINTR && errno != EAGAIN && | 296 | if (errno != EINTR && errno != EAGAIN && |
414 | errno != EWOULDBLOCK) { | 297 | errno != EWOULDBLOCK) { |
@@ -423,381 +306,26 @@ process_input(fd_set *readset) | |||
423 | packet_process_incoming(buf, len); | 306 | packet_process_incoming(buf, len); |
424 | } | 307 | } |
425 | } | 308 | } |
426 | if (compat20) | 309 | return 0; |
427 | return; | ||
428 | |||
429 | /* Read and buffer any available stdout data from the program. */ | ||
430 | if (!fdout_eof && FD_ISSET(fdout, readset)) { | ||
431 | errno = 0; | ||
432 | len = read(fdout, buf, sizeof(buf)); | ||
433 | if (len < 0 && (errno == EINTR || ((errno == EAGAIN || | ||
434 | errno == EWOULDBLOCK) && !child_terminated))) { | ||
435 | /* do nothing */ | ||
436 | #ifndef PTY_ZEROREAD | ||
437 | } else if (len <= 0) { | ||
438 | #else | ||
439 | } else if ((!isatty(fdout) && len <= 0) || | ||
440 | (isatty(fdout) && (len < 0 || (len == 0 && errno != 0)))) { | ||
441 | #endif | ||
442 | fdout_eof = 1; | ||
443 | } else { | ||
444 | buffer_append(&stdout_buffer, buf, len); | ||
445 | fdout_bytes += len; | ||
446 | } | ||
447 | } | ||
448 | /* Read and buffer any available stderr data from the program. */ | ||
449 | if (!fderr_eof && FD_ISSET(fderr, readset)) { | ||
450 | errno = 0; | ||
451 | len = read(fderr, buf, sizeof(buf)); | ||
452 | if (len < 0 && (errno == EINTR || ((errno == EAGAIN || | ||
453 | errno == EWOULDBLOCK) && !child_terminated))) { | ||
454 | /* do nothing */ | ||
455 | #ifndef PTY_ZEROREAD | ||
456 | } else if (len <= 0) { | ||
457 | #else | ||
458 | } else if ((!isatty(fderr) && len <= 0) || | ||
459 | (isatty(fderr) && (len < 0 || (len == 0 && errno != 0)))) { | ||
460 | #endif | ||
461 | fderr_eof = 1; | ||
462 | } else { | ||
463 | buffer_append(&stderr_buffer, buf, len); | ||
464 | } | ||
465 | } | ||
466 | } | 310 | } |
467 | 311 | ||
468 | /* | 312 | /* |
469 | * Sends data from internal buffers to client program stdin. | 313 | * Sends data from internal buffers to client program stdin. |
470 | */ | 314 | */ |
471 | static void | 315 | static void |
472 | process_output(fd_set *writeset) | 316 | process_output(fd_set *writeset, int connection_out) |
473 | { | 317 | { |
474 | struct termios tio; | ||
475 | u_char *data; | ||
476 | u_int dlen; | ||
477 | int len; | ||
478 | |||
479 | /* Write buffered data to program stdin. */ | ||
480 | if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) { | ||
481 | data = buffer_ptr(&stdin_buffer); | ||
482 | dlen = buffer_len(&stdin_buffer); | ||
483 | len = write(fdin, data, dlen); | ||
484 | if (len < 0 && | ||
485 | (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) { | ||
486 | /* do nothing */ | ||
487 | } else if (len <= 0) { | ||
488 | if (fdin != fdout) | ||
489 | close(fdin); | ||
490 | else | ||
491 | shutdown(fdin, SHUT_WR); /* We will no longer send. */ | ||
492 | fdin = -1; | ||
493 | } else { | ||
494 | /* Successful write. */ | ||
495 | if (fdin_is_tty && dlen >= 1 && data[0] != '\r' && | ||
496 | tcgetattr(fdin, &tio) == 0 && | ||
497 | !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) { | ||
498 | /* | ||
499 | * Simulate echo to reduce the impact of | ||
500 | * traffic analysis | ||
501 | */ | ||
502 | packet_send_ignore(len); | ||
503 | packet_send(); | ||
504 | } | ||
505 | /* Consume the data from the buffer. */ | ||
506 | buffer_consume(&stdin_buffer, len); | ||
507 | /* Update the count of bytes written to the program. */ | ||
508 | stdin_bytes += len; | ||
509 | } | ||
510 | } | ||
511 | /* Send any buffered packet data to the client. */ | 318 | /* Send any buffered packet data to the client. */ |
512 | if (FD_ISSET(connection_out, writeset)) | 319 | if (FD_ISSET(connection_out, writeset)) |
513 | packet_write_poll(); | 320 | packet_write_poll(); |
514 | } | 321 | } |
515 | 322 | ||
516 | /* | ||
517 | * Wait until all buffered output has been sent to the client. | ||
518 | * This is used when the program terminates. | ||
519 | */ | ||
520 | static void | ||
521 | drain_output(void) | ||
522 | { | ||
523 | /* Send any buffered stdout data to the client. */ | ||
524 | if (buffer_len(&stdout_buffer) > 0) { | ||
525 | packet_start(SSH_SMSG_STDOUT_DATA); | ||
526 | packet_put_string(buffer_ptr(&stdout_buffer), | ||
527 | buffer_len(&stdout_buffer)); | ||
528 | packet_send(); | ||
529 | /* Update the count of sent bytes. */ | ||
530 | stdout_bytes += buffer_len(&stdout_buffer); | ||
531 | } | ||
532 | /* Send any buffered stderr data to the client. */ | ||
533 | if (buffer_len(&stderr_buffer) > 0) { | ||
534 | packet_start(SSH_SMSG_STDERR_DATA); | ||
535 | packet_put_string(buffer_ptr(&stderr_buffer), | ||
536 | buffer_len(&stderr_buffer)); | ||
537 | packet_send(); | ||
538 | /* Update the count of sent bytes. */ | ||
539 | stderr_bytes += buffer_len(&stderr_buffer); | ||
540 | } | ||
541 | /* Wait until all buffered data has been written to the client. */ | ||
542 | packet_write_wait(); | ||
543 | } | ||
544 | |||
545 | static void | 323 | static void |
546 | process_buffered_input_packets(void) | 324 | process_buffered_input_packets(void) |
547 | { | 325 | { |
548 | dispatch_run(DISPATCH_NONBLOCK, NULL, active_state); | 326 | dispatch_run(DISPATCH_NONBLOCK, NULL, active_state); |
549 | } | 327 | } |
550 | 328 | ||
551 | /* | ||
552 | * Performs the interactive session. This handles data transmission between | ||
553 | * the client and the program. Note that the notion of stdin, stdout, and | ||
554 | * stderr in this function is sort of reversed: this function writes to | ||
555 | * stdin (of the child program), and reads from stdout and stderr (of the | ||
556 | * child program). | ||
557 | */ | ||
558 | void | ||
559 | server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) | ||
560 | { | ||
561 | fd_set *readset = NULL, *writeset = NULL; | ||
562 | int max_fd = 0; | ||
563 | u_int nalloc = 0; | ||
564 | int wait_status; /* Status returned by wait(). */ | ||
565 | pid_t wait_pid; /* pid returned by wait(). */ | ||
566 | int waiting_termination = 0; /* Have displayed waiting close message. */ | ||
567 | u_int64_t max_time_milliseconds; | ||
568 | u_int previous_stdout_buffer_bytes; | ||
569 | u_int stdout_buffer_bytes; | ||
570 | int type; | ||
571 | |||
572 | debug("Entering interactive session."); | ||
573 | |||
574 | /* Initialize the SIGCHLD kludge. */ | ||
575 | child_terminated = 0; | ||
576 | mysignal(SIGCHLD, sigchld_handler); | ||
577 | |||
578 | if (!use_privsep) { | ||
579 | signal(SIGTERM, sigterm_handler); | ||
580 | signal(SIGINT, sigterm_handler); | ||
581 | signal(SIGQUIT, sigterm_handler); | ||
582 | } | ||
583 | |||
584 | /* Initialize our global variables. */ | ||
585 | fdin = fdin_arg; | ||
586 | fdout = fdout_arg; | ||
587 | fderr = fderr_arg; | ||
588 | |||
589 | /* nonblocking IO */ | ||
590 | set_nonblock(fdin); | ||
591 | set_nonblock(fdout); | ||
592 | /* we don't have stderr for interactive terminal sessions, see below */ | ||
593 | if (fderr != -1) | ||
594 | set_nonblock(fderr); | ||
595 | |||
596 | if (!(datafellows & SSH_BUG_IGNOREMSG) && isatty(fdin)) | ||
597 | fdin_is_tty = 1; | ||
598 | |||
599 | connection_in = packet_get_connection_in(); | ||
600 | connection_out = packet_get_connection_out(); | ||
601 | |||
602 | notify_setup(); | ||
603 | |||
604 | previous_stdout_buffer_bytes = 0; | ||
605 | |||
606 | /* Set approximate I/O buffer size. */ | ||
607 | if (packet_is_interactive()) | ||
608 | buffer_high = 4096; | ||
609 | else | ||
610 | buffer_high = 64 * 1024; | ||
611 | |||
612 | #if 0 | ||
613 | /* Initialize max_fd to the maximum of the known file descriptors. */ | ||
614 | max_fd = MAX(connection_in, connection_out); | ||
615 | max_fd = MAX(max_fd, fdin); | ||
616 | max_fd = MAX(max_fd, fdout); | ||
617 | if (fderr != -1) | ||
618 | max_fd = MAX(max_fd, fderr); | ||
619 | #endif | ||
620 | |||
621 | /* Initialize Initialize buffers. */ | ||
622 | buffer_init(&stdin_buffer); | ||
623 | buffer_init(&stdout_buffer); | ||
624 | buffer_init(&stderr_buffer); | ||
625 | |||
626 | /* | ||
627 | * If we have no separate fderr (which is the case when we have a pty | ||
628 | * - there we cannot make difference between data sent to stdout and | ||
629 | * stderr), indicate that we have seen an EOF from stderr. This way | ||
630 | * we don't need to check the descriptor everywhere. | ||
631 | */ | ||
632 | if (fderr == -1) | ||
633 | fderr_eof = 1; | ||
634 | |||
635 | server_init_dispatch(); | ||
636 | |||
637 | /* Main loop of the server for the interactive session mode. */ | ||
638 | for (;;) { | ||
639 | |||
640 | /* Process buffered packets from the client. */ | ||
641 | process_buffered_input_packets(); | ||
642 | |||
643 | /* | ||
644 | * If we have received eof, and there is no more pending | ||
645 | * input data, cause a real eof by closing fdin. | ||
646 | */ | ||
647 | if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) { | ||
648 | if (fdin != fdout) | ||
649 | close(fdin); | ||
650 | else | ||
651 | shutdown(fdin, SHUT_WR); /* We will no longer send. */ | ||
652 | fdin = -1; | ||
653 | } | ||
654 | /* Make packets from buffered stderr data to send to the client. */ | ||
655 | make_packets_from_stderr_data(); | ||
656 | |||
657 | /* | ||
658 | * Make packets from buffered stdout data to send to the | ||
659 | * client. If there is very little to send, this arranges to | ||
660 | * not send them now, but to wait a short while to see if we | ||
661 | * are getting more data. This is necessary, as some systems | ||
662 | * wake up readers from a pty after each separate character. | ||
663 | */ | ||
664 | max_time_milliseconds = 0; | ||
665 | stdout_buffer_bytes = buffer_len(&stdout_buffer); | ||
666 | if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 256 && | ||
667 | stdout_buffer_bytes != previous_stdout_buffer_bytes) { | ||
668 | /* try again after a while */ | ||
669 | max_time_milliseconds = 10; | ||
670 | } else { | ||
671 | /* Send it now. */ | ||
672 | make_packets_from_stdout_data(); | ||
673 | } | ||
674 | previous_stdout_buffer_bytes = buffer_len(&stdout_buffer); | ||
675 | |||
676 | /* Send channel data to the client. */ | ||
677 | if (packet_not_very_much_data_to_write()) | ||
678 | channel_output_poll(); | ||
679 | |||
680 | /* | ||
681 | * Bail out of the loop if the program has closed its output | ||
682 | * descriptors, and we have no more data to send to the | ||
683 | * client, and there is no pending buffered data. | ||
684 | */ | ||
685 | if (fdout_eof && fderr_eof && !packet_have_data_to_write() && | ||
686 | buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) { | ||
687 | if (!channel_still_open()) | ||
688 | break; | ||
689 | if (!waiting_termination) { | ||
690 | const char *s = "Waiting for forwarded connections to terminate...\r\n"; | ||
691 | char *cp; | ||
692 | waiting_termination = 1; | ||
693 | buffer_append(&stderr_buffer, s, strlen(s)); | ||
694 | |||
695 | /* Display list of open channels. */ | ||
696 | cp = channel_open_message(); | ||
697 | buffer_append(&stderr_buffer, cp, strlen(cp)); | ||
698 | free(cp); | ||
699 | } | ||
700 | } | ||
701 | max_fd = MAX(connection_in, connection_out); | ||
702 | max_fd = MAX(max_fd, fdin); | ||
703 | max_fd = MAX(max_fd, fdout); | ||
704 | max_fd = MAX(max_fd, fderr); | ||
705 | max_fd = MAX(max_fd, notify_pipe[0]); | ||
706 | |||
707 | /* Sleep in select() until we can do something. */ | ||
708 | wait_until_can_do_something(&readset, &writeset, &max_fd, | ||
709 | &nalloc, max_time_milliseconds); | ||
710 | |||
711 | if (received_sigterm) { | ||
712 | logit("Exiting on signal %d", (int)received_sigterm); | ||
713 | /* Clean up sessions, utmp, etc. */ | ||
714 | cleanup_exit(255); | ||
715 | } | ||
716 | |||
717 | /* Process any channel events. */ | ||
718 | channel_after_select(readset, writeset); | ||
719 | |||
720 | /* Process input from the client and from program stdout/stderr. */ | ||
721 | process_input(readset); | ||
722 | |||
723 | /* Process output to the client and to program stdin. */ | ||
724 | process_output(writeset); | ||
725 | } | ||
726 | free(readset); | ||
727 | free(writeset); | ||
728 | |||
729 | /* Cleanup and termination code. */ | ||
730 | |||
731 | /* Wait until all output has been sent to the client. */ | ||
732 | drain_output(); | ||
733 | |||
734 | debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.", | ||
735 | stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes); | ||
736 | |||
737 | /* Free and clear the buffers. */ | ||
738 | buffer_free(&stdin_buffer); | ||
739 | buffer_free(&stdout_buffer); | ||
740 | buffer_free(&stderr_buffer); | ||
741 | |||
742 | /* Close the file descriptors. */ | ||
743 | if (fdout != -1) | ||
744 | close(fdout); | ||
745 | fdout = -1; | ||
746 | fdout_eof = 1; | ||
747 | if (fderr != -1) | ||
748 | close(fderr); | ||
749 | fderr = -1; | ||
750 | fderr_eof = 1; | ||
751 | if (fdin != -1) | ||
752 | close(fdin); | ||
753 | fdin = -1; | ||
754 | |||
755 | channel_free_all(); | ||
756 | |||
757 | /* We no longer want our SIGCHLD handler to be called. */ | ||
758 | mysignal(SIGCHLD, SIG_DFL); | ||
759 | |||
760 | while ((wait_pid = waitpid(-1, &wait_status, 0)) < 0) | ||
761 | if (errno != EINTR) | ||
762 | packet_disconnect("wait: %.100s", strerror(errno)); | ||
763 | if (wait_pid != pid) | ||
764 | error("Strange, wait returned pid %ld, expected %ld", | ||
765 | (long)wait_pid, (long)pid); | ||
766 | |||
767 | /* Check if it exited normally. */ | ||
768 | if (WIFEXITED(wait_status)) { | ||
769 | /* Yes, normal exit. Get exit status and send it to the client. */ | ||
770 | debug("Command exited with status %d.", WEXITSTATUS(wait_status)); | ||
771 | packet_start(SSH_SMSG_EXITSTATUS); | ||
772 | packet_put_int(WEXITSTATUS(wait_status)); | ||
773 | packet_send(); | ||
774 | packet_write_wait(); | ||
775 | |||
776 | /* | ||
777 | * Wait for exit confirmation. Note that there might be | ||
778 | * other packets coming before it; however, the program has | ||
779 | * already died so we just ignore them. The client is | ||
780 | * supposed to respond with the confirmation when it receives | ||
781 | * the exit status. | ||
782 | */ | ||
783 | do { | ||
784 | type = packet_read(); | ||
785 | } | ||
786 | while (type != SSH_CMSG_EXIT_CONFIRMATION); | ||
787 | |||
788 | debug("Received exit confirmation."); | ||
789 | return; | ||
790 | } | ||
791 | /* Check if the program terminated due to a signal. */ | ||
792 | if (WIFSIGNALED(wait_status)) | ||
793 | packet_disconnect("Command terminated on signal %d.", | ||
794 | WTERMSIG(wait_status)); | ||
795 | |||
796 | /* Some weird exit cause. Just exit. */ | ||
797 | packet_disconnect("wait returned status %04x.", wait_status); | ||
798 | /* NOTREACHED */ | ||
799 | } | ||
800 | |||
801 | static void | 329 | static void |
802 | collect_children(void) | 330 | collect_children(void) |
803 | { | 331 | { |
@@ -825,7 +353,7 @@ server_loop2(Authctxt *authctxt) | |||
825 | { | 353 | { |
826 | fd_set *readset = NULL, *writeset = NULL; | 354 | fd_set *readset = NULL, *writeset = NULL; |
827 | int max_fd; | 355 | int max_fd; |
828 | u_int nalloc = 0; | 356 | u_int nalloc = 0, connection_in, connection_out; |
829 | u_int64_t rekey_timeout_ms = 0; | 357 | u_int64_t rekey_timeout_ms = 0; |
830 | 358 | ||
831 | debug("Entering interactive session for SSH2."); | 359 | debug("Entering interactive session for SSH2."); |
@@ -843,8 +371,8 @@ server_loop2(Authctxt *authctxt) | |||
843 | 371 | ||
844 | notify_setup(); | 372 | notify_setup(); |
845 | 373 | ||
846 | max_fd = MAX(connection_in, connection_out); | 374 | max_fd = MAXIMUM(connection_in, connection_out); |
847 | max_fd = MAX(max_fd, notify_pipe[0]); | 375 | max_fd = MAXIMUM(max_fd, notify_pipe[0]); |
848 | 376 | ||
849 | server_init_dispatch(); | 377 | server_init_dispatch(); |
850 | 378 | ||
@@ -854,14 +382,14 @@ server_loop2(Authctxt *authctxt) | |||
854 | if (!ssh_packet_is_rekeying(active_state) && | 382 | if (!ssh_packet_is_rekeying(active_state) && |
855 | packet_not_very_much_data_to_write()) | 383 | packet_not_very_much_data_to_write()) |
856 | channel_output_poll(); | 384 | channel_output_poll(); |
857 | if (options.rekey_interval > 0 && compat20 && | 385 | if (options.rekey_interval > 0 && |
858 | !ssh_packet_is_rekeying(active_state)) | 386 | !ssh_packet_is_rekeying(active_state)) |
859 | rekey_timeout_ms = packet_get_rekey_timeout() * 1000; | 387 | rekey_timeout_ms = packet_get_rekey_timeout() * 1000; |
860 | else | 388 | else |
861 | rekey_timeout_ms = 0; | 389 | rekey_timeout_ms = 0; |
862 | 390 | ||
863 | wait_until_can_do_something(&readset, &writeset, &max_fd, | 391 | wait_until_can_do_something(connection_in, connection_out, |
864 | &nalloc, rekey_timeout_ms); | 392 | &readset, &writeset, &max_fd, &nalloc, rekey_timeout_ms); |
865 | 393 | ||
866 | if (received_sigterm) { | 394 | if (received_sigterm) { |
867 | logit("Exiting on signal %d", (int)received_sigterm); | 395 | logit("Exiting on signal %d", (int)received_sigterm); |
@@ -872,10 +400,9 @@ server_loop2(Authctxt *authctxt) | |||
872 | collect_children(); | 400 | collect_children(); |
873 | if (!ssh_packet_is_rekeying(active_state)) | 401 | if (!ssh_packet_is_rekeying(active_state)) |
874 | channel_after_select(readset, writeset); | 402 | channel_after_select(readset, writeset); |
875 | process_input(readset); | 403 | if (process_input(readset, connection_in) < 0) |
876 | if (connection_closed) | ||
877 | break; | 404 | break; |
878 | process_output(writeset); | 405 | process_output(writeset, connection_out); |
879 | } | 406 | } |
880 | collect_children(); | 407 | collect_children(); |
881 | 408 | ||
@@ -902,53 +429,6 @@ server_input_keep_alive(int type, u_int32_t seq, void *ctxt) | |||
902 | return 0; | 429 | return 0; |
903 | } | 430 | } |
904 | 431 | ||
905 | static int | ||
906 | server_input_stdin_data(int type, u_int32_t seq, void *ctxt) | ||
907 | { | ||
908 | char *data; | ||
909 | u_int data_len; | ||
910 | |||
911 | /* Stdin data from the client. Append it to the buffer. */ | ||
912 | /* Ignore any data if the client has closed stdin. */ | ||
913 | if (fdin == -1) | ||
914 | return 0; | ||
915 | data = packet_get_string(&data_len); | ||
916 | packet_check_eom(); | ||
917 | buffer_append(&stdin_buffer, data, data_len); | ||
918 | explicit_bzero(data, data_len); | ||
919 | free(data); | ||
920 | return 0; | ||
921 | } | ||
922 | |||
923 | static int | ||
924 | server_input_eof(int type, u_int32_t seq, void *ctxt) | ||
925 | { | ||
926 | /* | ||
927 | * Eof from the client. The stdin descriptor to the | ||
928 | * program will be closed when all buffered data has | ||
929 | * drained. | ||
930 | */ | ||
931 | debug("EOF received for stdin."); | ||
932 | packet_check_eom(); | ||
933 | stdin_eof = 1; | ||
934 | return 0; | ||
935 | } | ||
936 | |||
937 | static int | ||
938 | server_input_window_size(int type, u_int32_t seq, void *ctxt) | ||
939 | { | ||
940 | u_int row = packet_get_int(); | ||
941 | u_int col = packet_get_int(); | ||
942 | u_int xpixel = packet_get_int(); | ||
943 | u_int ypixel = packet_get_int(); | ||
944 | |||
945 | debug("Window change received."); | ||
946 | packet_check_eom(); | ||
947 | if (fdin != -1) | ||
948 | pty_change_window_size(fdin, row, col, xpixel, ypixel); | ||
949 | return 0; | ||
950 | } | ||
951 | |||
952 | static Channel * | 432 | static Channel * |
953 | server_request_direct_tcpip(void) | 433 | server_request_direct_tcpip(void) |
954 | { | 434 | { |
@@ -967,7 +447,7 @@ server_request_direct_tcpip(void) | |||
967 | 447 | ||
968 | /* XXX fine grained permissions */ | 448 | /* XXX fine grained permissions */ |
969 | if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0 && | 449 | if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0 && |
970 | !no_port_forwarding_flag) { | 450 | !no_port_forwarding_flag && !options.disable_forwarding) { |
971 | c = channel_connect_to_port(target, target_port, | 451 | c = channel_connect_to_port(target, target_port, |
972 | "direct-tcpip", "direct-tcpip"); | 452 | "direct-tcpip", "direct-tcpip"); |
973 | } else { | 453 | } else { |
@@ -999,7 +479,8 @@ server_request_direct_streamlocal(void) | |||
999 | 479 | ||
1000 | /* XXX fine grained permissions */ | 480 | /* XXX fine grained permissions */ |
1001 | if ((options.allow_streamlocal_forwarding & FORWARD_LOCAL) != 0 && | 481 | if ((options.allow_streamlocal_forwarding & FORWARD_LOCAL) != 0 && |
1002 | !no_port_forwarding_flag) { | 482 | !no_port_forwarding_flag && !options.disable_forwarding && |
483 | use_privsep) { | ||
1003 | c = channel_connect_to_path(target, | 484 | c = channel_connect_to_path(target, |
1004 | "direct-streamlocal@openssh.com", "direct-streamlocal"); | 485 | "direct-streamlocal@openssh.com", "direct-streamlocal"); |
1005 | } else { | 486 | } else { |
@@ -1242,10 +723,10 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt) | |||
1242 | 723 | ||
1243 | /* check permissions */ | 724 | /* check permissions */ |
1244 | if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0 || | 725 | if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0 || |
1245 | no_port_forwarding_flag || | 726 | no_port_forwarding_flag || options.disable_forwarding || |
1246 | (!want_reply && fwd.listen_port == 0) || | 727 | (!want_reply && fwd.listen_port == 0) || |
1247 | (fwd.listen_port != 0 && fwd.listen_port < IPPORT_RESERVED && | 728 | (fwd.listen_port != 0 && |
1248 | pw->pw_uid != 0)) { | 729 | !bind_permitted(fwd.listen_port, pw->pw_uid))) { |
1249 | success = 0; | 730 | success = 0; |
1250 | packet_send_debug("Server has disabled port forwarding."); | 731 | packet_send_debug("Server has disabled port forwarding."); |
1251 | } else { | 732 | } else { |
@@ -1280,7 +761,8 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt) | |||
1280 | 761 | ||
1281 | /* check permissions */ | 762 | /* check permissions */ |
1282 | if ((options.allow_streamlocal_forwarding & FORWARD_REMOTE) == 0 | 763 | if ((options.allow_streamlocal_forwarding & FORWARD_REMOTE) == 0 |
1283 | || no_port_forwarding_flag) { | 764 | || no_port_forwarding_flag || options.disable_forwarding || |
765 | !use_privsep) { | ||
1284 | success = 0; | 766 | success = 0; |
1285 | packet_send_debug("Server has disabled port forwarding."); | 767 | packet_send_debug("Server has disabled port forwarding."); |
1286 | } else { | 768 | } else { |
@@ -1353,9 +835,9 @@ server_input_channel_req(int type, u_int32_t seq, void *ctxt) | |||
1353 | } | 835 | } |
1354 | 836 | ||
1355 | static void | 837 | static void |
1356 | server_init_dispatch_20(void) | 838 | server_init_dispatch(void) |
1357 | { | 839 | { |
1358 | debug("server_init_dispatch_20"); | 840 | debug("server_init_dispatch"); |
1359 | dispatch_init(&dispatch_protocol_error); | 841 | dispatch_init(&dispatch_protocol_error); |
1360 | dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose); | 842 | dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose); |
1361 | dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data); | 843 | dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data); |
@@ -1375,36 +857,3 @@ server_init_dispatch_20(void) | |||
1375 | /* rekeying */ | 857 | /* rekeying */ |
1376 | dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); | 858 | dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); |
1377 | } | 859 | } |
1378 | static void | ||
1379 | server_init_dispatch_13(void) | ||
1380 | { | ||
1381 | debug("server_init_dispatch_13"); | ||
1382 | dispatch_init(NULL); | ||
1383 | dispatch_set(SSH_CMSG_EOF, &server_input_eof); | ||
1384 | dispatch_set(SSH_CMSG_STDIN_DATA, &server_input_stdin_data); | ||
1385 | dispatch_set(SSH_CMSG_WINDOW_SIZE, &server_input_window_size); | ||
1386 | dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close); | ||
1387 | dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation); | ||
1388 | dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data); | ||
1389 | dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); | ||
1390 | dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); | ||
1391 | dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open); | ||
1392 | } | ||
1393 | static void | ||
1394 | server_init_dispatch_15(void) | ||
1395 | { | ||
1396 | server_init_dispatch_13(); | ||
1397 | debug("server_init_dispatch_15"); | ||
1398 | dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); | ||
1399 | dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose); | ||
1400 | } | ||
1401 | static void | ||
1402 | server_init_dispatch(void) | ||
1403 | { | ||
1404 | if (compat20) | ||
1405 | server_init_dispatch_20(); | ||
1406 | else if (compat13) | ||
1407 | server_init_dispatch_13(); | ||
1408 | else | ||
1409 | server_init_dispatch_15(); | ||
1410 | } | ||