X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/5641aefacbf337c20520df4ffe5c87333241356d..a8539f66aef3ef34ecab4cec0a04dab5bf46ee5f:/serverloop.c diff --git a/serverloop.c b/serverloop.c index 6c8719a3..eee1e795 100644 --- a/serverloop.c +++ b/serverloop.c @@ -35,13 +35,14 @@ */ #include "includes.h" -RCSID("$OpenBSD: serverloop.c,v 1.95 2002/01/16 13:17:51 markus Exp $"); +RCSID("$OpenBSD: serverloop.c,v 1.117 2004/08/11 21:43:05 avsm Exp $"); #include "xmalloc.h" #include "packet.h" #include "buffer.h" #include "log.h" #include "servconf.h" +#include "canohost.h" #include "sshpty.h" #include "channels.h" #include "compat.h" @@ -59,7 +60,7 @@ extern ServerOptions options; /* XXX */ extern Kex *xxx_kex; -static Authctxt *xxx_authctxt; +extern Authctxt *the_authctxt; static Buffer stdin_buffer; /* Buffer for stdin data. */ static Buffer stdout_buffer; /* Buffer for stdout data. */ @@ -143,7 +144,9 @@ sigchld_handler(int sig) int save_errno = errno; debug("Received SIGCHLD."); child_terminated = 1; +#ifndef _UNICOS mysignal(SIGCHLD, sigchld_handler); +#endif notify_parent(); errno = save_errno; } @@ -155,7 +158,7 @@ sigchld_handler(int sig) static void make_packets_from_stderr_data(void) { - int len; + u_int len; /* Send buffered stderr data to the client. */ while (buffer_len(&stderr_buffer) > 0 && @@ -184,7 +187,7 @@ make_packets_from_stderr_data(void) static void make_packets_from_stdout_data(void) { - int len; + u_int len; /* Send buffered stdout data to the client. */ while (buffer_len(&stdout_buffer) > 0 && @@ -209,26 +212,23 @@ make_packets_from_stdout_data(void) static void client_alive_check(void) { - static int had_channel = 0; - int id; - - id = channel_find_open(); - if (id == -1) { - if (!had_channel) - return; - packet_disconnect("No open channels after timeout!"); - } - had_channel = 1; + int channel_id; /* timeout, check to see how many we have had */ if (++client_alive_timeouts > options.client_alive_count_max) packet_disconnect("Timeout, your session not responding."); /* - * send a bogus channel request with "wantreply", + * send a bogus global/channel request with "wantreply", * we should get back a failure */ - channel_request_start(id, "keepalive@openssh.com", 1); + if ((channel_id = channel_find_open()) == -1) { + packet_start(SSH2_MSG_GLOBAL_REQUEST); + packet_put_cstring("keepalive@openssh.com"); + packet_put_char(1); /* boolean: want reply */ + } else { + channel_request_start(channel_id, "keepalive@openssh.com", 1); + } packet_send(); } @@ -240,7 +240,7 @@ client_alive_check(void) */ static void wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, - int *nallocp, u_int max_time_milliseconds) + u_int *nallocp, u_int max_time_milliseconds) { struct timeval tv, *tvp; int ret; @@ -318,9 +318,6 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, tv.tv_usec = 1000 * (max_time_milliseconds % 1000); tvp = &tv; } - if (tvp!=NULL) - debug3("tvp!=NULL kid %d mili %d", (int) child_terminated, - max_time_milliseconds); /* Wait for something to happen, or the timeout to expire. */ ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); @@ -350,15 +347,18 @@ process_input(fd_set * readset) if (FD_ISSET(connection_in, readset)) { len = read(connection_in, buf, sizeof(buf)); if (len == 0) { - verbose("Connection closed by remote host."); + verbose("Connection closed by %.100s", + get_remote_ipaddr()); connection_closed = 1; if (compat20) return; - fatal_cleanup(); + cleanup_exit(255); } else if (len < 0) { if (errno != EINTR && errno != EAGAIN) { - verbose("Read error from remote host: %.100s", strerror(errno)); - fatal_cleanup(); + verbose("Read error from remote host " + "%.100s: %.100s", + get_remote_ipaddr(), strerror(errno)); + cleanup_exit(255); } } else { /* Buffer any received data. */ @@ -486,7 +486,8 @@ void server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) { fd_set *readset = NULL, *writeset = NULL; - int max_fd = 0, nalloc = 0; + int max_fd = 0; + u_int nalloc = 0; int wait_status; /* Status returned by wait(). */ pid_t wait_pid; /* pid returned by wait(). */ int waiting_termination = 0; /* Have displayed waiting close message. */ @@ -673,12 +674,12 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) /* We no longer want our SIGCHLD handler to be called. */ mysignal(SIGCHLD, SIG_DFL); - wait_pid = waitpid(-1, &wait_status, child_terminated ? WNOHANG : 0); - if (wait_pid == -1) - packet_disconnect("wait: %.100s", strerror(errno)); - else if (wait_pid != pid) - error("Strange, wait returned pid %d, expected %d", - wait_pid, pid); + while ((wait_pid = waitpid(-1, &wait_status, 0)) < 0) + if (errno != EINTR) + packet_disconnect("wait: %.100s", strerror(errno)); + if (wait_pid != pid) + error("Strange, wait returned pid %ld, expected %ld", + (long)wait_pid, (long)pid); /* Check if it exited normally. */ if (WIFEXITED(wait_status)) { @@ -726,8 +727,10 @@ collect_children(void) sigaddset(&nset, SIGCHLD); sigprocmask(SIG_BLOCK, &nset, &oset); if (child_terminated) { - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) - session_close_by_pid(pid, status); + while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || + (pid < 0 && errno == EINTR)) + if (pid > 0) + session_close_by_pid(pid, status); child_terminated = 0; } sigprocmask(SIG_SETMASK, &oset, NULL); @@ -751,8 +754,6 @@ server_loop2(Authctxt *authctxt) max_fd = MAX(connection_in, connection_out); max_fd = MAX(max_fd, notify_pipe[0]); - xxx_authctxt = authctxt; - server_init_dispatch(); for (;;) { @@ -766,8 +767,14 @@ server_loop2(Authctxt *authctxt) &nalloc, 0); collect_children(); - if (!rekeying) + if (!rekeying) { channel_after_select(readset, writeset); + if (packet_need_rekeying()) { + debug("need rekeying"); + xxx_kex->done = 0; + kex_send_kexinit(xxx_kex); + } + } process_input(readset); if (connection_closed) break; @@ -784,13 +791,13 @@ server_loop2(Authctxt *authctxt) channel_free_all(); /* free remaining sessions, e.g. remove wtmp entries */ - session_destroy_all(); + session_destroy_all(NULL); } static void -server_input_channel_failure(int type, u_int32_t seq, void *ctxt) +server_input_keep_alive(int type, u_int32_t seq, void *ctxt) { - debug("Got CHANNEL_FAILURE for keepalive"); + debug("Got %d/%u for keepalive", type, seq); /* * reset timeout, since we got a sane answer from the client. * even if this was generated by something other than @@ -799,7 +806,6 @@ server_input_channel_failure(int type, u_int32_t seq, void *ctxt) client_alive_timeouts = 0; } - static void server_input_stdin_data(int type, u_int32_t seq, void *ctxt) { @@ -845,7 +851,7 @@ server_input_window_size(int type, u_int32_t seq, void *ctxt) } static Channel * -server_request_direct_tcpip(char *ctype) +server_request_direct_tcpip(void) { Channel *c; int sock; @@ -867,18 +873,14 @@ server_request_direct_tcpip(char *ctype) xfree(originator); if (sock < 0) return NULL; - c = channel_new(ctype, SSH_CHANNEL_CONNECTING, + c = channel_new("direct-tcpip", SSH_CHANNEL_CONNECTING, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, - CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("direct-tcpip"), 1); - if (c == NULL) { - error("server_request_direct_tcpip: channel_new failed"); - close(sock); - } + CHAN_TCP_PACKET_DEFAULT, 0, "direct-tcpip", 1); return c; } static Channel * -server_request_session(char *ctype) +server_request_session(void) { Channel *c; @@ -890,20 +892,14 @@ server_request_session(char *ctype) * SSH_CHANNEL_LARVAL. Additionally, a callback for handling all * CHANNEL_REQUEST messages is registered. */ - c = channel_new(ctype, SSH_CHANNEL_LARVAL, + c = channel_new("session", SSH_CHANNEL_LARVAL, -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT, - 0, xstrdup("server-session"), 1); - if (c == NULL) { - error("server_request_session: channel_new failed"); - return NULL; - } - if (session_open(xxx_authctxt, c->self) != 1) { + 0, "server-session", 1); + if (session_open(the_authctxt, c->self) != 1) { debug("session open failed, free channel %d", c->self); channel_free(c); return NULL; } - channel_register_callback(c->self, SSH2_MSG_CHANNEL_REQUEST, - session_input_channel_req, (void *)0); channel_register_cleanup(c->self, session_close_by_channel); return c; } @@ -913,10 +909,8 @@ server_input_channel_open(int type, u_int32_t seq, void *ctxt) { Channel *c = NULL; char *ctype; - u_int len; int rchan; - int rmaxpack; - int rwindow; + u_int rmaxpack, rwindow, len; ctype = packet_get_string(&len); rchan = packet_get_int(); @@ -927,9 +921,9 @@ server_input_channel_open(int type, u_int32_t seq, void *ctxt) ctype, rchan, rwindow, rmaxpack); if (strcmp(ctype, "session") == 0) { - c = server_request_session(ctype); + c = server_request_session(); } else if (strcmp(ctype, "direct-tcpip") == 0) { - c = server_request_direct_tcpip(ctype); + c = server_request_direct_tcpip(); } if (c != NULL) { debug("server_input_channel_open: confirm %s", ctype); @@ -975,18 +969,21 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt) char *listen_address; u_short listen_port; - pw = auth_get_user(); - if (pw == NULL) - fatal("server_input_global_request: no user"); - listen_address = packet_get_string(NULL); /* XXX currently ignored */ + pw = the_authctxt->pw; + if (pw == NULL || !the_authctxt->valid) + fatal("server_input_global_request: no/invalid user"); + listen_address = packet_get_string(NULL); listen_port = (u_short)packet_get_int(); debug("server_input_global_request: tcpip-forward listen %s port %d", listen_address, listen_port); /* check permissions */ if (!options.allow_tcp_forwarding || - no_port_forwarding_flag || - (listen_port < IPPORT_RESERVED && pw->pw_uid != 0)) { + no_port_forwarding_flag +#ifndef NO_IPPORT_RESERVED_CONCEPT + || (listen_port < IPPORT_RESERVED && pw->pw_uid != 0) +#endif + ) { success = 0; packet_send_debug("Server has disabled port forwarding."); } else { @@ -995,6 +992,17 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt) listen_address, listen_port, options.gateway_ports); } xfree(listen_address); + } else if (strcmp(rtype, "cancel-tcpip-forward") == 0) { + char *cancel_address; + u_short cancel_port; + + cancel_address = packet_get_string(NULL); + cancel_port = (u_short)packet_get_int(); + debug("%s: cancel-tcpip-forward addr %s port %d", __func__, + cancel_address, cancel_port); + + success = channel_cancel_rport_listener(cancel_address, + cancel_port); } if (want_reply) { packet_start(success ? @@ -1004,6 +1012,33 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt) } xfree(rtype); } +static void +server_input_channel_req(int type, u_int32_t seq, void *ctxt) +{ + Channel *c; + int id, reply, success = 0; + char *rtype; + + id = packet_get_int(); + rtype = packet_get_string(NULL); + reply = packet_get_char(); + + debug("server_input_channel_req: channel %d request %s reply %d", + id, rtype, reply); + + if ((c = channel_lookup(id)) == NULL) + packet_disconnect("server_input_channel_req: " + "unknown channel %d", id); + if (c->type == SSH_CHANNEL_LARVAL || c->type == SSH_CHANNEL_OPEN) + success = session_input_channel_req(c, rtype); + if (reply) { + packet_start(success ? + SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE); + packet_put_int(c->remote_id); + packet_send(); + } + xfree(rtype); +} static void server_init_dispatch_20(void) @@ -1017,11 +1052,13 @@ server_init_dispatch_20(void) dispatch_set(SSH2_MSG_CHANNEL_OPEN, &server_input_channel_open); dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); - dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request); + dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &server_input_channel_req); dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request); /* client_alive */ - dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_channel_failure); + dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_keep_alive); + dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &server_input_keep_alive); + dispatch_set(SSH2_MSG_REQUEST_FAILURE, &server_input_keep_alive); /* rekeying */ dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); }