diff options
Diffstat (limited to 'serverloop.c')
-rw-r--r-- | serverloop.c | 60 |
1 files changed, 37 insertions, 23 deletions
diff --git a/serverloop.c b/serverloop.c index 29ffcfee1..6a3e2af10 100644 --- a/serverloop.c +++ b/serverloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: serverloop.c,v 1.145 2006/10/11 12:38:03 markus Exp $ */ | 1 | /* $OpenBSD: serverloop.c,v 1.153 2008/06/30 12:15:39 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 |
@@ -56,6 +56,7 @@ | |||
56 | #include <unistd.h> | 56 | #include <unistd.h> |
57 | #include <stdarg.h> | 57 | #include <stdarg.h> |
58 | 58 | ||
59 | #include "openbsd-compat/sys-queue.h" | ||
59 | #include "xmalloc.h" | 60 | #include "xmalloc.h" |
60 | #include "packet.h" | 61 | #include "packet.h" |
61 | #include "buffer.h" | 62 | #include "buffer.h" |
@@ -104,7 +105,7 @@ static int connection_in; /* Connection to client (input). */ | |||
104 | static int connection_out; /* Connection to client (output). */ | 105 | static int connection_out; /* Connection to client (output). */ |
105 | static int connection_closed = 0; /* Connection to client closed. */ | 106 | static int connection_closed = 0; /* Connection to client closed. */ |
106 | static u_int buffer_high; /* "Soft" max buffer size. */ | 107 | static u_int buffer_high; /* "Soft" max buffer size. */ |
107 | static int client_alive_timeouts = 0; | 108 | static int no_more_sessions = 0; /* Disallow further sessions. */ |
108 | 109 | ||
109 | /* | 110 | /* |
110 | * This SIGCHLD kludge is used to detect when the child exits. The server | 111 | * This SIGCHLD kludge is used to detect when the child exits. The server |
@@ -248,7 +249,7 @@ client_alive_check(void) | |||
248 | int channel_id; | 249 | int channel_id; |
249 | 250 | ||
250 | /* timeout, check to see how many we have had */ | 251 | /* timeout, check to see how many we have had */ |
251 | if (++client_alive_timeouts > options.client_alive_count_max) { | 252 | if (++keep_alive_timeouts > options.client_alive_count_max) { |
252 | logit("Timeout, client not responding."); | 253 | logit("Timeout, client not responding."); |
253 | cleanup_exit(255); | 254 | cleanup_exit(255); |
254 | } | 255 | } |
@@ -399,7 +400,8 @@ process_input(fd_set *readset) | |||
399 | return; | 400 | return; |
400 | cleanup_exit(255); | 401 | cleanup_exit(255); |
401 | } else if (len < 0) { | 402 | } else if (len < 0) { |
402 | if (errno != EINTR && errno != EAGAIN) { | 403 | if (errno != EINTR && errno != EAGAIN && |
404 | errno != EWOULDBLOCK) { | ||
403 | verbose("Read error from remote host " | 405 | verbose("Read error from remote host " |
404 | "%.100s: %.100s", | 406 | "%.100s: %.100s", |
405 | get_remote_ipaddr(), strerror(errno)); | 407 | get_remote_ipaddr(), strerror(errno)); |
@@ -417,8 +419,8 @@ process_input(fd_set *readset) | |||
417 | if (!fdout_eof && FD_ISSET(fdout, readset)) { | 419 | if (!fdout_eof && FD_ISSET(fdout, readset)) { |
418 | errno = 0; | 420 | errno = 0; |
419 | len = read(fdout, buf, sizeof(buf)); | 421 | len = read(fdout, buf, sizeof(buf)); |
420 | if (len < 0 && (errno == EINTR || | 422 | if (len < 0 && (errno == EINTR || ((errno == EAGAIN || |
421 | (errno == EAGAIN && !child_terminated))) { | 423 | errno == EWOULDBLOCK) && !child_terminated))) { |
422 | /* do nothing */ | 424 | /* do nothing */ |
423 | #ifndef PTY_ZEROREAD | 425 | #ifndef PTY_ZEROREAD |
424 | } else if (len <= 0) { | 426 | } else if (len <= 0) { |
@@ -436,8 +438,8 @@ process_input(fd_set *readset) | |||
436 | if (!fderr_eof && FD_ISSET(fderr, readset)) { | 438 | if (!fderr_eof && FD_ISSET(fderr, readset)) { |
437 | errno = 0; | 439 | errno = 0; |
438 | len = read(fderr, buf, sizeof(buf)); | 440 | len = read(fderr, buf, sizeof(buf)); |
439 | if (len < 0 && (errno == EINTR || | 441 | if (len < 0 && (errno == EINTR || ((errno == EAGAIN || |
440 | (errno == EAGAIN && !child_terminated))) { | 442 | errno == EWOULDBLOCK) && !child_terminated))) { |
441 | /* do nothing */ | 443 | /* do nothing */ |
442 | #ifndef PTY_ZEROREAD | 444 | #ifndef PTY_ZEROREAD |
443 | } else if (len <= 0) { | 445 | } else if (len <= 0) { |
@@ -468,7 +470,8 @@ process_output(fd_set *writeset) | |||
468 | data = buffer_ptr(&stdin_buffer); | 470 | data = buffer_ptr(&stdin_buffer); |
469 | dlen = buffer_len(&stdin_buffer); | 471 | dlen = buffer_len(&stdin_buffer); |
470 | len = write(fdin, data, dlen); | 472 | len = write(fdin, data, dlen); |
471 | if (len < 0 && (errno == EINTR || errno == EAGAIN)) { | 473 | if (len < 0 && |
474 | (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) { | ||
472 | /* do nothing */ | 475 | /* do nothing */ |
473 | } else if (len <= 0) { | 476 | } else if (len <= 0) { |
474 | if (fdin != fdout) | 477 | if (fdin != fdout) |
@@ -887,7 +890,7 @@ server_input_keep_alive(int type, u_int32_t seq, void *ctxt) | |||
887 | * even if this was generated by something other than | 890 | * even if this was generated by something other than |
888 | * the bogus CHANNEL_REQUEST we send for keepalives. | 891 | * the bogus CHANNEL_REQUEST we send for keepalives. |
889 | */ | 892 | */ |
890 | client_alive_timeouts = 0; | 893 | keep_alive_timeouts = 0; |
891 | } | 894 | } |
892 | 895 | ||
893 | static void | 896 | static void |
@@ -938,7 +941,6 @@ static Channel * | |||
938 | server_request_direct_tcpip(void) | 941 | server_request_direct_tcpip(void) |
939 | { | 942 | { |
940 | Channel *c; | 943 | Channel *c; |
941 | int sock; | ||
942 | char *target, *originator; | 944 | char *target, *originator; |
943 | int target_port, originator_port; | 945 | int target_port, originator_port; |
944 | 946 | ||
@@ -948,18 +950,16 @@ server_request_direct_tcpip(void) | |||
948 | originator_port = packet_get_int(); | 950 | originator_port = packet_get_int(); |
949 | packet_check_eom(); | 951 | packet_check_eom(); |
950 | 952 | ||
951 | debug("server_request_direct_tcpip: originator %s port %d, target %s port %d", | 953 | debug("server_request_direct_tcpip: originator %s port %d, target %s " |
952 | originator, originator_port, target, target_port); | 954 | "port %d", originator, originator_port, target, target_port); |
953 | 955 | ||
954 | /* XXX check permission */ | 956 | /* XXX check permission */ |
955 | sock = channel_connect_to(target, target_port); | 957 | c = channel_connect_to(target, target_port, |
956 | xfree(target); | 958 | "direct-tcpip", "direct-tcpip"); |
959 | |||
957 | xfree(originator); | 960 | xfree(originator); |
958 | if (sock < 0) | 961 | xfree(target); |
959 | return NULL; | 962 | |
960 | c = channel_new("direct-tcpip", SSH_CHANNEL_CONNECTING, | ||
961 | sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, | ||
962 | CHAN_TCP_PACKET_DEFAULT, 0, "direct-tcpip", 1); | ||
963 | return c; | 963 | return c; |
964 | } | 964 | } |
965 | 965 | ||
@@ -1000,7 +1000,7 @@ server_request_tun(void) | |||
1000 | #if defined(SSH_TUN_FILTER) | 1000 | #if defined(SSH_TUN_FILTER) |
1001 | if (mode == SSH_TUNMODE_POINTOPOINT) | 1001 | if (mode == SSH_TUNMODE_POINTOPOINT) |
1002 | channel_register_filter(c->self, sys_tun_infilter, | 1002 | channel_register_filter(c->self, sys_tun_infilter, |
1003 | sys_tun_outfilter); | 1003 | sys_tun_outfilter, NULL, NULL); |
1004 | #endif | 1004 | #endif |
1005 | 1005 | ||
1006 | done: | 1006 | done: |
@@ -1016,6 +1016,12 @@ server_request_session(void) | |||
1016 | 1016 | ||
1017 | debug("input_session_request"); | 1017 | debug("input_session_request"); |
1018 | packet_check_eom(); | 1018 | packet_check_eom(); |
1019 | |||
1020 | if (no_more_sessions) { | ||
1021 | packet_disconnect("Possible attack: attempt to open a session " | ||
1022 | "after additional sessions disabled"); | ||
1023 | } | ||
1024 | |||
1019 | /* | 1025 | /* |
1020 | * A server session has no fd to read or write until a | 1026 | * A server session has no fd to read or write until a |
1021 | * CHANNEL_REQUEST for a shell is made, so we set the type to | 1027 | * CHANNEL_REQUEST for a shell is made, so we set the type to |
@@ -1136,6 +1142,9 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt) | |||
1136 | success = channel_cancel_rport_listener(cancel_address, | 1142 | success = channel_cancel_rport_listener(cancel_address, |
1137 | cancel_port); | 1143 | cancel_port); |
1138 | xfree(cancel_address); | 1144 | xfree(cancel_address); |
1145 | } else if (strcmp(rtype, "no-more-sessions@openssh.com") == 0) { | ||
1146 | no_more_sessions = 1; | ||
1147 | success = 1; | ||
1139 | } | 1148 | } |
1140 | if (want_reply) { | 1149 | if (want_reply) { |
1141 | packet_start(success ? | 1150 | packet_start(success ? |
@@ -1163,7 +1172,11 @@ server_input_channel_req(int type, u_int32_t seq, void *ctxt) | |||
1163 | if ((c = channel_lookup(id)) == NULL) | 1172 | if ((c = channel_lookup(id)) == NULL) |
1164 | packet_disconnect("server_input_channel_req: " | 1173 | packet_disconnect("server_input_channel_req: " |
1165 | "unknown channel %d", id); | 1174 | "unknown channel %d", id); |
1166 | if (c->type == SSH_CHANNEL_LARVAL || c->type == SSH_CHANNEL_OPEN) | 1175 | if (!strcmp(rtype, "eow@openssh.com")) { |
1176 | packet_check_eom(); | ||
1177 | chan_rcvd_eow(c); | ||
1178 | } else if ((c->type == SSH_CHANNEL_LARVAL || | ||
1179 | c->type == SSH_CHANNEL_OPEN) && strcmp(c->ctype, "session") == 0) | ||
1167 | success = session_input_channel_req(c, rtype); | 1180 | success = session_input_channel_req(c, rtype); |
1168 | if (reply) { | 1181 | if (reply) { |
1169 | packet_start(success ? | 1182 | packet_start(success ? |
@@ -1189,8 +1202,9 @@ server_init_dispatch_20(void) | |||
1189 | dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &server_input_channel_req); | 1202 | dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &server_input_channel_req); |
1190 | dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); | 1203 | dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); |
1191 | dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request); | 1204 | dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request); |
1205 | dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &channel_input_status_confirm); | ||
1206 | dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &channel_input_status_confirm); | ||
1192 | /* client_alive */ | 1207 | /* client_alive */ |
1193 | dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_keep_alive); | ||
1194 | dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &server_input_keep_alive); | 1208 | dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &server_input_keep_alive); |
1195 | dispatch_set(SSH2_MSG_REQUEST_FAILURE, &server_input_keep_alive); | 1209 | dispatch_set(SSH2_MSG_REQUEST_FAILURE, &server_input_keep_alive); |
1196 | /* rekeying */ | 1210 | /* rekeying */ |