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