diff options
Diffstat (limited to 'serverloop.c')
-rw-r--r-- | serverloop.c | 195 |
1 files changed, 93 insertions, 102 deletions
diff --git a/serverloop.c b/serverloop.c index 2afca7637..8bf448ceb 100644 --- a/serverloop.c +++ b/serverloop.c | |||
@@ -13,6 +13,10 @@ | |||
13 | #include "buffer.h" | 13 | #include "buffer.h" |
14 | #include "servconf.h" | 14 | #include "servconf.h" |
15 | #include "pty.h" | 15 | #include "pty.h" |
16 | #include "channels.h" | ||
17 | |||
18 | #include "compat.h" | ||
19 | #include "dispatch.h" | ||
16 | 20 | ||
17 | static Buffer stdin_buffer; /* Buffer for stdin data. */ | 21 | static Buffer stdin_buffer; /* Buffer for stdin data. */ |
18 | static Buffer stdout_buffer; /* Buffer for stdout data. */ | 22 | static Buffer stdout_buffer; /* Buffer for stdout data. */ |
@@ -47,6 +51,8 @@ static volatile int child_terminated; /* The child has terminated. */ | |||
47 | static volatile int child_has_selected; /* Child has had chance to drain. */ | 51 | static volatile int child_has_selected; /* Child has had chance to drain. */ |
48 | static volatile int child_wait_status; /* Status from wait(). */ | 52 | static volatile int child_wait_status; /* Status from wait(). */ |
49 | 53 | ||
54 | void server_init_dispatch(void); | ||
55 | |||
50 | void | 56 | void |
51 | sigchld_handler(int sig) | 57 | sigchld_handler(int sig) |
52 | { | 58 | { |
@@ -68,104 +74,6 @@ sigchld_handler(int sig) | |||
68 | } | 74 | } |
69 | 75 | ||
70 | /* | 76 | /* |
71 | * Process any buffered packets that have been received from the client. | ||
72 | */ | ||
73 | void | ||
74 | process_buffered_input_packets() | ||
75 | { | ||
76 | int type; | ||
77 | char *data; | ||
78 | unsigned int data_len; | ||
79 | int row, col, xpixel, ypixel; | ||
80 | int payload_len; | ||
81 | |||
82 | /* Process buffered packets from the client. */ | ||
83 | while ((type = packet_read_poll(&payload_len)) != SSH_MSG_NONE) { | ||
84 | switch (type) { | ||
85 | case SSH_CMSG_STDIN_DATA: | ||
86 | /* Stdin data from the client. Append it to the buffer. */ | ||
87 | /* Ignore any data if the client has closed stdin. */ | ||
88 | if (fdin == -1) | ||
89 | break; | ||
90 | data = packet_get_string(&data_len); | ||
91 | packet_integrity_check(payload_len, (4 + data_len), type); | ||
92 | buffer_append(&stdin_buffer, data, data_len); | ||
93 | memset(data, 0, data_len); | ||
94 | xfree(data); | ||
95 | break; | ||
96 | |||
97 | case SSH_CMSG_EOF: | ||
98 | /* | ||
99 | * Eof from the client. The stdin descriptor to the | ||
100 | * program will be closed when all buffered data has | ||
101 | * drained. | ||
102 | */ | ||
103 | debug("EOF received for stdin."); | ||
104 | packet_integrity_check(payload_len, 0, type); | ||
105 | stdin_eof = 1; | ||
106 | break; | ||
107 | |||
108 | case SSH_CMSG_WINDOW_SIZE: | ||
109 | debug("Window change received."); | ||
110 | packet_integrity_check(payload_len, 4 * 4, type); | ||
111 | row = packet_get_int(); | ||
112 | col = packet_get_int(); | ||
113 | xpixel = packet_get_int(); | ||
114 | ypixel = packet_get_int(); | ||
115 | if (fdin != -1) | ||
116 | pty_change_window_size(fdin, row, col, xpixel, ypixel); | ||
117 | break; | ||
118 | |||
119 | case SSH_MSG_PORT_OPEN: | ||
120 | debug("Received port open request."); | ||
121 | channel_input_port_open(payload_len); | ||
122 | break; | ||
123 | |||
124 | case SSH_MSG_CHANNEL_OPEN_CONFIRMATION: | ||
125 | debug("Received channel open confirmation."); | ||
126 | packet_integrity_check(payload_len, 4 + 4, type); | ||
127 | channel_input_open_confirmation(); | ||
128 | break; | ||
129 | |||
130 | case SSH_MSG_CHANNEL_OPEN_FAILURE: | ||
131 | debug("Received channel open failure."); | ||
132 | packet_integrity_check(payload_len, 4, type); | ||
133 | channel_input_open_failure(); | ||
134 | break; | ||
135 | |||
136 | case SSH_MSG_CHANNEL_DATA: | ||
137 | channel_input_data(payload_len); | ||
138 | break; | ||
139 | |||
140 | case SSH_MSG_CHANNEL_CLOSE: | ||
141 | debug("Received channel close."); | ||
142 | packet_integrity_check(payload_len, 4, type); | ||
143 | channel_input_close(); | ||
144 | break; | ||
145 | |||
146 | case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION: | ||
147 | debug("Received channel close confirmation."); | ||
148 | packet_integrity_check(payload_len, 4, type); | ||
149 | channel_input_close_confirmation(); | ||
150 | break; | ||
151 | |||
152 | default: | ||
153 | /* | ||
154 | * In this phase, any unexpected messages cause a | ||
155 | * protocol error. This is to ease debugging; also, | ||
156 | * since no confirmations are sent messages, | ||
157 | * unprocessed unknown messages could cause strange | ||
158 | * problems. Any compatible protocol extensions must | ||
159 | * be negotiated before entering the interactive | ||
160 | * session. | ||
161 | */ | ||
162 | packet_disconnect("Protocol error during session: type %d", | ||
163 | type); | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | |||
168 | /* | ||
169 | * Make packets from buffered stderr data, and buffer it for sending | 77 | * Make packets from buffered stderr data, and buffer it for sending |
170 | * to the client. | 78 | * to the client. |
171 | */ | 79 | */ |
@@ -378,7 +286,7 @@ process_output(fd_set * writeset) | |||
378 | #ifdef USE_PIPES | 286 | #ifdef USE_PIPES |
379 | close(fdin); | 287 | close(fdin); |
380 | #else | 288 | #else |
381 | if (fdout == -1) | 289 | if (fdin != fdout) |
382 | close(fdin); | 290 | close(fdin); |
383 | else | 291 | else |
384 | shutdown(fdin, SHUT_WR); /* We will no longer send. */ | 292 | shutdown(fdin, SHUT_WR); /* We will no longer send. */ |
@@ -425,6 +333,12 @@ drain_output() | |||
425 | packet_write_wait(); | 333 | packet_write_wait(); |
426 | } | 334 | } |
427 | 335 | ||
336 | void | ||
337 | process_buffered_input_packets() | ||
338 | { | ||
339 | dispatch_run(DISPATCH_NONBLOCK, NULL); | ||
340 | } | ||
341 | |||
428 | /* | 342 | /* |
429 | * Performs the interactive session. This handles data transmission between | 343 | * Performs the interactive session. This handles data transmission between |
430 | * the client and the program. Note that the notion of stdin, stdout, and | 344 | * the client and the program. Note that the notion of stdin, stdout, and |
@@ -490,6 +404,8 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg) | |||
490 | if (fderr == -1) | 404 | if (fderr == -1) |
491 | fderr_eof = 1; | 405 | fderr_eof = 1; |
492 | 406 | ||
407 | server_init_dispatch(); | ||
408 | |||
493 | /* Main loop of the server for the interactive session mode. */ | 409 | /* Main loop of the server for the interactive session mode. */ |
494 | for (;;) { | 410 | for (;;) { |
495 | fd_set readset, writeset; | 411 | fd_set readset, writeset; |
@@ -505,7 +421,7 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg) | |||
505 | #ifdef USE_PIPES | 421 | #ifdef USE_PIPES |
506 | close(fdin); | 422 | close(fdin); |
507 | #else | 423 | #else |
508 | if (fdout == -1) | 424 | if (fdin != fdout) |
509 | close(fdin); | 425 | close(fdin); |
510 | else | 426 | else |
511 | shutdown(fdin, SHUT_WR); /* We will no longer send. */ | 427 | shutdown(fdin, SHUT_WR); /* We will no longer send. */ |
@@ -549,7 +465,7 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg) | |||
549 | (buffer_len(&stdout_buffer) == 0) && | 465 | (buffer_len(&stdout_buffer) == 0) && |
550 | (buffer_len(&stderr_buffer) == 0)) { | 466 | (buffer_len(&stderr_buffer) == 0)) { |
551 | if (!channel_still_open()) | 467 | if (!channel_still_open()) |
552 | goto quit; | 468 | break; |
553 | if (!waiting_termination) { | 469 | if (!waiting_termination) { |
554 | const char *s = "Waiting for forwarded connections to terminate...\r\n"; | 470 | const char *s = "Waiting for forwarded connections to terminate...\r\n"; |
555 | char *cp; | 471 | char *cp; |
@@ -576,7 +492,6 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg) | |||
576 | process_output(&writeset); | 492 | process_output(&writeset); |
577 | } | 493 | } |
578 | 494 | ||
579 | quit: | ||
580 | /* Cleanup and termination code. */ | 495 | /* Cleanup and termination code. */ |
581 | 496 | ||
582 | /* Wait until all output has been sent to the client. */ | 497 | /* Wait until all output has been sent to the client. */ |
@@ -662,3 +577,79 @@ quit: | |||
662 | packet_disconnect("wait returned status %04x.", wait_status); | 577 | packet_disconnect("wait returned status %04x.", wait_status); |
663 | /* NOTREACHED */ | 578 | /* NOTREACHED */ |
664 | } | 579 | } |
580 | |||
581 | void | ||
582 | server_input_stdin_data(int type, int plen) | ||
583 | { | ||
584 | char *data; | ||
585 | unsigned int data_len; | ||
586 | |||
587 | /* Stdin data from the client. Append it to the buffer. */ | ||
588 | /* Ignore any data if the client has closed stdin. */ | ||
589 | if (fdin == -1) | ||
590 | return; | ||
591 | data = packet_get_string(&data_len); | ||
592 | packet_integrity_check(plen, (4 + data_len), type); | ||
593 | buffer_append(&stdin_buffer, data, data_len); | ||
594 | memset(data, 0, data_len); | ||
595 | xfree(data); | ||
596 | } | ||
597 | |||
598 | void | ||
599 | server_input_eof(int type, int plen) | ||
600 | { | ||
601 | /* | ||
602 | * Eof from the client. The stdin descriptor to the | ||
603 | * program will be closed when all buffered data has | ||
604 | * drained. | ||
605 | */ | ||
606 | debug("EOF received for stdin."); | ||
607 | packet_integrity_check(plen, 0, type); | ||
608 | stdin_eof = 1; | ||
609 | } | ||
610 | |||
611 | void | ||
612 | server_input_window_size(int type, int plen) | ||
613 | { | ||
614 | int row = packet_get_int(); | ||
615 | int col = packet_get_int(); | ||
616 | int xpixel = packet_get_int(); | ||
617 | int ypixel = packet_get_int(); | ||
618 | |||
619 | debug("Window change received."); | ||
620 | packet_integrity_check(plen, 4 * 4, type); | ||
621 | if (fdin != -1) | ||
622 | pty_change_window_size(fdin, row, col, xpixel, ypixel); | ||
623 | } | ||
624 | |||
625 | void | ||
626 | server_init_dispatch_13() | ||
627 | { | ||
628 | debug("server_init_dispatch_13"); | ||
629 | dispatch_init(NULL); | ||
630 | dispatch_set(SSH_CMSG_EOF, &server_input_eof); | ||
631 | dispatch_set(SSH_CMSG_STDIN_DATA, &server_input_stdin_data); | ||
632 | dispatch_set(SSH_CMSG_WINDOW_SIZE, &server_input_window_size); | ||
633 | dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close); | ||
634 | dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation); | ||
635 | dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data); | ||
636 | dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); | ||
637 | dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); | ||
638 | dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open); | ||
639 | } | ||
640 | void | ||
641 | server_init_dispatch_15() | ||
642 | { | ||
643 | server_init_dispatch_13(); | ||
644 | debug("server_init_dispatch_15"); | ||
645 | dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); | ||
646 | dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose); | ||
647 | } | ||
648 | void | ||
649 | server_init_dispatch() | ||
650 | { | ||
651 | if (compat13) | ||
652 | server_init_dispatch_13(); | ||
653 | else | ||
654 | server_init_dispatch_15(); | ||
655 | } | ||