]> andersk Git - openssh.git/blame - serverloop.c
- Merged very large OpenBSD source code reformat
[openssh.git] / serverloop.c
CommitLineData
8efc0c15 1/*
5260325f 2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 * All rights reserved
5 * Created: Sun Sep 10 00:30:37 1995 ylo
6 * Server main loop for handling the interactive session.
7 */
8efc0c15 8
9#include "includes.h"
10#include "xmalloc.h"
11#include "ssh.h"
12#include "packet.h"
13#include "buffer.h"
14#include "servconf.h"
15#include "pty.h"
16
17static Buffer stdin_buffer; /* Buffer for stdin data. */
18static Buffer stdout_buffer; /* Buffer for stdout data. */
19static Buffer stderr_buffer; /* Buffer for stderr data. */
20static int fdin; /* Descriptor for stdin (for writing) */
21static int fdout; /* Descriptor for stdout (for reading);
22 May be same number as fdin. */
23static int fderr; /* Descriptor for stderr. May be -1. */
24static long stdin_bytes = 0; /* Number of bytes written to stdin. */
25static long stdout_bytes = 0; /* Number of stdout bytes sent to client. */
26static long stderr_bytes = 0; /* Number of stderr bytes sent to client. */
27static long fdout_bytes = 0; /* Number of stdout bytes read from program. */
28static int stdin_eof = 0; /* EOF message received from client. */
29static int fdout_eof = 0; /* EOF encountered reading from fdout. */
30static int fderr_eof = 0; /* EOF encountered readung from fderr. */
31static int connection_in; /* Connection to client (input). */
32static int connection_out; /* Connection to client (output). */
33static unsigned int buffer_high;/* "Soft" max buffer size. */
34static int max_fd; /* Max file descriptor number for select(). */
35
36/* This SIGCHLD kludge is used to detect when the child exits. The server
37 will exit after that, as soon as forwarded connections have terminated. */
38
5260325f 39static int child_pid; /* Pid of the child. */
8efc0c15 40static volatile int child_terminated; /* The child has terminated. */
41static volatile int child_wait_status; /* Status from wait(). */
42
5260325f 43void
44sigchld_handler(int sig)
8efc0c15 45{
5260325f 46 int save_errno = errno;
47 int wait_pid;
48 debug("Received SIGCHLD.");
49 wait_pid = wait((int *) &child_wait_status);
50 if (wait_pid != -1) {
51 if (wait_pid != child_pid)
52 error("Strange, got SIGCHLD and wait returned pid %d but child is %d",
53 wait_pid, child_pid);
54 if (WIFEXITED(child_wait_status) ||
55 WIFSIGNALED(child_wait_status))
56 child_terminated = 1;
57 }
58 signal(SIGCHLD, sigchld_handler);
59 errno = save_errno;
8efc0c15 60}
61
5260325f 62/*
63 * Process any buffered packets that have been received from the client.
64 */
65void
66process_buffered_input_packets()
8efc0c15 67{
5260325f 68 int type;
69 char *data;
70 unsigned int data_len;
71 int row, col, xpixel, ypixel;
72 int payload_len;
73
74 /* Process buffered packets from the client. */
75 while ((type = packet_read_poll(&payload_len)) != SSH_MSG_NONE) {
76 switch (type) {
77 case SSH_CMSG_STDIN_DATA:
78 /* Stdin data from the client. Append it to the buffer. */
79 /* Ignore any data if the client has closed stdin. */
80 if (fdin == -1)
81 break;
82 data = packet_get_string(&data_len);
83 packet_integrity_check(payload_len, (4 + data_len), type);
84 buffer_append(&stdin_buffer, data, data_len);
85 memset(data, 0, data_len);
86 xfree(data);
87 break;
88
89 case SSH_CMSG_EOF:
90 /* Eof from the client. The stdin descriptor to
91 the program will be closed when all buffered
92 data has drained. */
93 debug("EOF received for stdin.");
94 packet_integrity_check(payload_len, 0, type);
95 stdin_eof = 1;
96 break;
97
98 case SSH_CMSG_WINDOW_SIZE:
99 debug("Window change received.");
100 packet_integrity_check(payload_len, 4 * 4, type);
101 row = packet_get_int();
102 col = packet_get_int();
103 xpixel = packet_get_int();
104 ypixel = packet_get_int();
105 if (fdin != -1)
106 pty_change_window_size(fdin, row, col, xpixel, ypixel);
107 break;
108
109 case SSH_MSG_PORT_OPEN:
110 debug("Received port open request.");
111 channel_input_port_open(payload_len);
112 break;
113
114 case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
115 debug("Received channel open confirmation.");
116 packet_integrity_check(payload_len, 4 + 4, type);
117 channel_input_open_confirmation();
118 break;
119
120 case SSH_MSG_CHANNEL_OPEN_FAILURE:
121 debug("Received channel open failure.");
122 packet_integrity_check(payload_len, 4, type);
123 channel_input_open_failure();
124 break;
125
126 case SSH_MSG_CHANNEL_DATA:
127 channel_input_data(payload_len);
128 break;
129
130 case SSH_MSG_CHANNEL_CLOSE:
131 debug("Received channel close.");
132 packet_integrity_check(payload_len, 4, type);
133 channel_input_close();
134 break;
135
136 case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION:
137 debug("Received channel close confirmation.");
138 packet_integrity_check(payload_len, 4, type);
139 channel_input_close_confirmation();
140 break;
141
142 default:
143 /* In this phase, any unexpected messages cause a
144 protocol error. This is to ease debugging;
145 also, since no confirmations are sent messages,
146 unprocessed unknown messages could cause
147 strange problems. Any compatible protocol
148 extensions must be negotiated before entering
149 the interactive session. */
150 packet_disconnect("Protocol error during session: type %d",
151 type);
152 }
8efc0c15 153 }
8efc0c15 154}
155
5260325f 156/*
157 * Make packets from buffered stderr data, and buffer it for sending
158 * to the client.
159 */
160void
161make_packets_from_stderr_data()
8efc0c15 162{
5260325f 163 int len;
164
165 /* Send buffered stderr data to the client. */
166 while (buffer_len(&stderr_buffer) > 0 &&
167 packet_not_very_much_data_to_write()) {
168 len = buffer_len(&stderr_buffer);
169 if (packet_is_interactive()) {
170 if (len > 512)
171 len = 512;
172 } else {
173 /* Keep the packets at reasonable size. */
174 if (len > packet_get_maxsize())
175 len = packet_get_maxsize();
176 }
177 packet_start(SSH_SMSG_STDERR_DATA);
178 packet_put_string(buffer_ptr(&stderr_buffer), len);
179 packet_send();
180 buffer_consume(&stderr_buffer, len);
181 stderr_bytes += len;
8efc0c15 182 }
8efc0c15 183}
184
5260325f 185/*
186 * Make packets from buffered stdout data, and buffer it for sending to the
187 * client.
188 */
189void
190make_packets_from_stdout_data()
8efc0c15 191{
5260325f 192 int len;
193
194 /* Send buffered stdout data to the client. */
195 while (buffer_len(&stdout_buffer) > 0 &&
196 packet_not_very_much_data_to_write()) {
197 len = buffer_len(&stdout_buffer);
198 if (packet_is_interactive()) {
199 if (len > 512)
200 len = 512;
201 } else {
202 /* Keep the packets at reasonable size. */
203 if (len > packet_get_maxsize())
204 len = packet_get_maxsize();
205 }
206 packet_start(SSH_SMSG_STDOUT_DATA);
207 packet_put_string(buffer_ptr(&stdout_buffer), len);
208 packet_send();
209 buffer_consume(&stdout_buffer, len);
210 stdout_bytes += len;
8efc0c15 211 }
8efc0c15 212}
213
5260325f 214/*
215 * Sleep in select() until we can do something. This will initialize the
216 * select masks. Upon return, the masks will indicate which descriptors
217 * have data or can accept data. Optionally, a maximum time can be specified
218 * for the duration of the wait (0 = infinite).
219 */
220void
221wait_until_can_do_something(fd_set * readset, fd_set * writeset,
222 unsigned int max_time_milliseconds)
8efc0c15 223{
5260325f 224 struct timeval tv, *tvp;
225 int ret;
8efc0c15 226
5260325f 227 /* When select fails we restart from here. */
8efc0c15 228retry_select:
229
5260325f 230 /* Initialize select() masks. */
231 FD_ZERO(readset);
232
233 /* Read packets from the client unless we have too much buffered
234 stdin or channel data. */
235 if (buffer_len(&stdin_buffer) < 4096 &&
236 channel_not_very_much_buffered_data())
237 FD_SET(connection_in, readset);
238
239 /* If there is not too much data already buffered going to the
240 client, try to get some more data from the program. */
241 if (packet_not_very_much_data_to_write()) {
242 if (!fdout_eof)
243 FD_SET(fdout, readset);
244 if (!fderr_eof)
245 FD_SET(fderr, readset);
246 }
247 FD_ZERO(writeset);
248
249 /* Set masks for channel descriptors. */
250 channel_prepare_select(readset, writeset);
251
252 /* If we have buffered packet data going to the client, mark that
253 descriptor. */
254 if (packet_have_data_to_write())
255 FD_SET(connection_out, writeset);
256
257 /* If we have buffered data, try to write some of that data to the
258 program. */
259 if (fdin != -1 && buffer_len(&stdin_buffer) > 0)
260 FD_SET(fdin, writeset);
261
262 /* Update the maximum descriptor number if appropriate. */
263 if (channel_max_fd() > max_fd)
264 max_fd = channel_max_fd();
265
266 /* If child has terminated and there is enough buffer space to
267 read from it, then read as much as is available and exit. */
268 if (child_terminated && packet_not_very_much_data_to_write())
269 if (max_time_milliseconds == 0)
270 max_time_milliseconds = 100;
271
272 if (max_time_milliseconds == 0)
273 tvp = NULL;
274 else {
275 tv.tv_sec = max_time_milliseconds / 1000;
276 tv.tv_usec = 1000 * (max_time_milliseconds % 1000);
277 tvp = &tv;
278 }
8efc0c15 279
5260325f 280 /* Wait for something to happen, or the timeout to expire. */
281 ret = select(max_fd + 1, readset, writeset, NULL, tvp);
8efc0c15 282
5260325f 283 if (ret < 0) {
284 if (errno != EINTR)
285 error("select: %.100s", strerror(errno));
286 else
287 goto retry_select;
8efc0c15 288 }
8efc0c15 289}
290
5260325f 291/*
292 * Processes input from the client and the program. Input data is stored
293 * in buffers and processed later.
294 */
295void
296process_input(fd_set * readset)
297{
298 int len;
299 char buf[16384];
300
301 /* Read and buffer any input data from the client. */
302 if (FD_ISSET(connection_in, readset)) {
303 len = read(connection_in, buf, sizeof(buf));
304 if (len == 0) {
305 verbose("Connection closed by remote host.");
306 fatal_cleanup();
307 }
308 /* There is a kernel bug on Solaris that causes select to
309 sometimes wake up even though there is no data
310 available. */
311 if (len < 0 && errno == EAGAIN)
312 len = 0;
313
314 if (len < 0) {
315 verbose("Read error from remote host: %.100s", strerror(errno));
316 fatal_cleanup();
317 }
318 /* Buffer any received data. */
319 packet_process_incoming(buf, len);
320 }
321 /* Read and buffer any available stdout data from the program. */
322 if (!fdout_eof && FD_ISSET(fdout, readset)) {
323 len = read(fdout, buf, sizeof(buf));
324 if (len <= 0)
325 fdout_eof = 1;
326 else {
327 buffer_append(&stdout_buffer, buf, len);
328 fdout_bytes += len;
329 }
330 }
331 /* Read and buffer any available stderr data from the program. */
332 if (!fderr_eof && FD_ISSET(fderr, readset)) {
333 len = read(fderr, buf, sizeof(buf));
334 if (len <= 0)
335 fderr_eof = 1;
336 else
337 buffer_append(&stderr_buffer, buf, len);
338 }
339}
8efc0c15 340
5260325f 341/*
342 * Sends data from internal buffers to client program stdin.
343 */
344void
345process_output(fd_set * writeset)
8efc0c15 346{
5260325f 347 int len;
348
349 /* Write buffered data to program stdin. */
350 if (fdin != -1 && FD_ISSET(fdin, writeset)) {
351 len = write(fdin, buffer_ptr(&stdin_buffer),
352 buffer_len(&stdin_buffer));
353 if (len <= 0) {
8efc0c15 354#ifdef USE_PIPES
5260325f 355 close(fdin);
8efc0c15 356#else
5260325f 357 if (fdout == -1)
358 close(fdin);
359 else
360 shutdown(fdin, SHUT_WR); /* We will no longer send. */
8efc0c15 361#endif
5260325f 362 fdin = -1;
363 } else {
364 /* Successful write. Consume the data from the buffer. */
365 buffer_consume(&stdin_buffer, len);
366 /* Update the count of bytes written to the program. */
367 stdin_bytes += len;
368 }
8efc0c15 369 }
5260325f 370 /* Send any buffered packet data to the client. */
371 if (FD_ISSET(connection_out, writeset))
372 packet_write_poll();
8efc0c15 373}
374
5260325f 375/*
376 * Wait until all buffered output has been sent to the client.
377 * This is used when the program terminates.
378 */
379void
380drain_output()
8efc0c15 381{
5260325f 382 /* Send any buffered stdout data to the client. */
383 if (buffer_len(&stdout_buffer) > 0) {
384 packet_start(SSH_SMSG_STDOUT_DATA);
385 packet_put_string(buffer_ptr(&stdout_buffer),
386 buffer_len(&stdout_buffer));
387 packet_send();
388 /* Update the count of sent bytes. */
389 stdout_bytes += buffer_len(&stdout_buffer);
390 }
391 /* Send any buffered stderr data to the client. */
392 if (buffer_len(&stderr_buffer) > 0) {
393 packet_start(SSH_SMSG_STDERR_DATA);
394 packet_put_string(buffer_ptr(&stderr_buffer),
395 buffer_len(&stderr_buffer));
396 packet_send();
397 /* Update the count of sent bytes. */
398 stderr_bytes += buffer_len(&stderr_buffer);
399 }
400 /* Wait until all buffered data has been written to the client. */
401 packet_write_wait();
8efc0c15 402}
403
5260325f 404/*
405 * Performs the interactive session. This handles data transmission between
406 * the client and the program. Note that the notion of stdin, stdout, and
407 * stderr in this function is sort of reversed: this function writes to
408 * stdin (of the child program), and reads from stdout and stderr (of the
409 * child program).
410 */
411void
412server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
8efc0c15 413{
5260325f 414 int wait_status, wait_pid; /* Status and pid returned by wait(). */
415 int waiting_termination = 0; /* Have displayed waiting close message. */
416 unsigned int max_time_milliseconds;
417 unsigned int previous_stdout_buffer_bytes;
418 unsigned int stdout_buffer_bytes;
419 int type;
420
421 debug("Entering interactive session.");
422
423 /* Initialize the SIGCHLD kludge. */
424 child_pid = pid;
425 child_terminated = 0;
426 signal(SIGCHLD, sigchld_handler);
427
428 /* Initialize our global variables. */
429 fdin = fdin_arg;
430 fdout = fdout_arg;
431 fderr = fderr_arg;
432 connection_in = packet_get_connection_in();
433 connection_out = packet_get_connection_out();
434
435 previous_stdout_buffer_bytes = 0;
436
437 /* Set approximate I/O buffer size. */
438 if (packet_is_interactive())
439 buffer_high = 4096;
440 else
441 buffer_high = 64 * 1024;
442
443 /* Initialize max_fd to the maximum of the known file descriptors. */
444 max_fd = fdin;
445 if (fdout > max_fd)
446 max_fd = fdout;
447 if (fderr != -1 && fderr > max_fd)
448 max_fd = fderr;
449 if (connection_in > max_fd)
450 max_fd = connection_in;
451 if (connection_out > max_fd)
452 max_fd = connection_out;
453
454 /* Initialize Initialize buffers. */
455 buffer_init(&stdin_buffer);
456 buffer_init(&stdout_buffer);
457 buffer_init(&stderr_buffer);
458
459 /* If we have no separate fderr (which is the case when we have a
460 pty - there we cannot make difference between data sent to
461 stdout and stderr), indicate that we have seen an EOF from
462 stderr. This way we don\'t need to check the descriptor
463 everywhere. */
464 if (fderr == -1)
465 fderr_eof = 1;
466
467 /* Main loop of the server for the interactive session mode. */
468 for (;;) {
469 fd_set readset, writeset;
470
471 /* Process buffered packets from the client. */
472 process_buffered_input_packets();
473
474 /* If we have received eof, and there is no more pending
475 input data, cause a real eof by closing fdin. */
476 if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) {
8efc0c15 477#ifdef USE_PIPES
5260325f 478 close(fdin);
8efc0c15 479#else
5260325f 480 if (fdout == -1)
481 close(fdin);
482 else
483 shutdown(fdin, SHUT_WR); /* We will no longer send. */
8efc0c15 484#endif
5260325f 485 fdin = -1;
486 }
487 /* Make packets from buffered stderr data to send to the
488 client. */
489 make_packets_from_stderr_data();
490
491 /* Make packets from buffered stdout data to send to the
492 client. If there is very little to send, this arranges
493 to not send them now, but to wait a short while to see
494 if we are getting more data. This is necessary, as some
495 systems wake up readers from a pty after each separate
496 character. */
497 max_time_milliseconds = 0;
498 stdout_buffer_bytes = buffer_len(&stdout_buffer);
499 if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 256 &&
500 stdout_buffer_bytes != previous_stdout_buffer_bytes) {
501 /* try again after a while */
502 max_time_milliseconds = 10;
503 } else {
504 /* Send it now. */
505 make_packets_from_stdout_data();
506 }
507 previous_stdout_buffer_bytes = buffer_len(&stdout_buffer);
508
509 /* Send channel data to the client. */
510 if (packet_not_very_much_data_to_write())
511 channel_output_poll();
512
513 /* Bail out of the loop if the program has closed its
514 output descriptors, and we have no more data to send to
515 the client, and there is no pending buffered data. */
516 if (fdout_eof && fderr_eof && !packet_have_data_to_write() &&
517 buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) {
518 if (!channel_still_open())
519 goto quit;
520 if (!waiting_termination) {
521 const char *s = "Waiting for forwarded connections to terminate...\r\n";
522 char *cp;
523 waiting_termination = 1;
524 buffer_append(&stderr_buffer, s, strlen(s));
525
526 /* Display list of open channels. */
527 cp = channel_open_message();
528 buffer_append(&stderr_buffer, cp, strlen(cp));
529 xfree(cp);
530 }
531 }
532 /* Sleep in select() until we can do something. */
533 wait_until_can_do_something(&readset, &writeset,
534 max_time_milliseconds);
535
536 /* Process any channel events. */
537 channel_after_select(&readset, &writeset);
538
539 /* Process input from the client and from program stdout/stderr. */
540 process_input(&readset);
541
542 /* Process output to the client and to program stdin. */
543 process_output(&writeset);
8efc0c15 544 }
545
5260325f 546quit:
547 /* Cleanup and termination code. */
8efc0c15 548
5260325f 549 /* Wait until all output has been sent to the client. */
550 drain_output();
8efc0c15 551
5260325f 552 debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.",
553 stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes);
8efc0c15 554
5260325f 555 /* Free and clear the buffers. */
556 buffer_free(&stdin_buffer);
557 buffer_free(&stdout_buffer);
558 buffer_free(&stderr_buffer);
8efc0c15 559
5260325f 560 /* Close the file descriptors. */
561 if (fdout != -1)
562 close(fdout);
563 fdout = -1;
564 fdout_eof = 1;
565 if (fderr != -1)
566 close(fderr);
567 fderr = -1;
568 fderr_eof = 1;
569 if (fdin != -1)
570 close(fdin);
571 fdin = -1;
572
573 /* Stop listening for channels; this removes unix domain sockets. */
574 channel_stop_listening();
575
576 /* Wait for the child to exit. Get its exit status. */
577 wait_pid = wait(&wait_status);
578 if (wait_pid < 0) {
579 /*
580 * It is possible that the wait was handled by SIGCHLD
581 * handler. This may result in either: this call
582 * returning with EINTR, or: this call returning ECHILD.
583 */
584 if (child_terminated)
585 wait_status = child_wait_status;
586 else
587 packet_disconnect("wait: %.100s", strerror(errno));
588 } else {
589 /* Check if it matches the process we forked. */
590 if (wait_pid != pid)
591 error("Strange, wait returned pid %d, expected %d",
592 wait_pid, pid);
593 }
8efc0c15 594
5260325f 595 /* We no longer want our SIGCHLD handler to be called. */
596 signal(SIGCHLD, SIG_DFL);
597
598 /* Check if it exited normally. */
599 if (WIFEXITED(wait_status)) {
600 /* Yes, normal exit. Get exit status and send it to the client. */
601 debug("Command exited with status %d.", WEXITSTATUS(wait_status));
602 packet_start(SSH_SMSG_EXITSTATUS);
603 packet_put_int(WEXITSTATUS(wait_status));
604 packet_send();
605 packet_write_wait();
606
607 /* Wait for exit confirmation. Note that there might be
608 other packets coming before it; however, the program
609 has already died so we just ignore them. The client is
610 supposed to respond with the confirmation when it
611 receives the exit status. */
612 do {
613 int plen;
614 type = packet_read(&plen);
615 }
616 while (type != SSH_CMSG_EXIT_CONFIRMATION);
617
618 debug("Received exit confirmation.");
619 return;
620 }
621 /* Check if the program terminated due to a signal. */
622 if (WIFSIGNALED(wait_status))
623 packet_disconnect("Command terminated on signal %d.",
624 WTERMSIG(wait_status));
625
626 /* Some weird exit cause. Just exit. */
627 packet_disconnect("wait returned status %04x.", wait_status);
628 /* NOTREACHED */
629}
This page took 0.193173 seconds and 5 git commands to generate.