]> andersk Git - openssh.git/blobdiff - serverloop.c
Added in Linux's select issue to TODO. Which may have to do with the
[openssh.git] / serverloop.c
index a9e478764218b8e2e607f44dc1610eebe150d812..d1816b52cccf2d49c971e542e58211e0a8090f10 100644 (file)
@@ -35,6 +35,8 @@
  */
 
 #include "includes.h"
+RCSID("$OpenBSD: serverloop.c,v 1.35 2000/11/06 23:04:56 markus Exp $");
+
 #include "xmalloc.h"
 #include "ssh.h"
 #include "packet.h"
@@ -48,6 +50,7 @@
 #include "session.h"
 #include "dispatch.h"
 #include "auth-options.h"
+#include "auth.h"
 
 extern ServerOptions options;
 
@@ -73,15 +76,10 @@ static int max_fd;          /* Max file descriptor number for select(). */
 /*
  * This SIGCHLD kludge is used to detect when the child exits.  The server
  * will exit after that, as soon as forwarded connections have terminated.
- *
- * After SIGCHLD child_has_selected is set to 1 after the first pass
- * through the wait_until_can_do_something() select(). This ensures
- * that the child's output gets a chance to drain before it is yanked.
  */
 
 static pid_t child_pid;                        /* Pid of the child. */
 static volatile int child_terminated;  /* The child has terminated. */
-static volatile int child_has_selected; /* Child has had chance to drain. */
 static volatile int child_wait_status; /* Status from wait(). */
 
 void   server_init_dispatch(void);
@@ -99,10 +97,8 @@ sigchld_handler(int sig)
                        error("Strange, got SIGCHLD and wait returned pid %d but child is %d",
                              wait_pid, child_pid);
                if (WIFEXITED(child_wait_status) ||
-                   WIFSIGNALED(child_wait_status)) {
+                   WIFSIGNALED(child_wait_status))
                        child_terminated = 1;
-                       child_has_selected = 0;
-               }
        }
        signal(SIGCHLD, sigchld_handler);
        errno = save_errno;
@@ -113,7 +109,7 @@ sigchld_handler2(int sig)
        int save_errno = errno;
        debug("Received SIGCHLD.");
        child_terminated = 1;
-       child_has_selected = 0;
+       signal(SIGCHLD, sigchld_handler2);
        errno = save_errno;
 }
 
@@ -265,9 +261,6 @@ retry_select:
                else
                        goto retry_select;
        }
-       
-       if (child_terminated)
-               child_has_selected = 1;
 }
 
 /*
@@ -419,7 +412,6 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
        /* Initialize the SIGCHLD kludge. */
        child_pid = pid;
        child_terminated = 0;
-       child_has_selected = 0;
        signal(SIGCHLD, sigchld_handler);
        signal(SIGPIPE, SIG_IGN);
 
@@ -525,11 +517,8 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
                 * descriptors, and we have no more data to send to the
                 * client, and there is no pending buffered data.
                 */
-               if (((fdout_eof && fderr_eof) || 
-                   (child_terminated && child_has_selected)) && 
-                   !packet_have_data_to_write() &&
-                   (buffer_len(&stdout_buffer) == 0) && 
-                        (buffer_len(&stderr_buffer) == 0)) {
+               if (fdout_eof && fderr_eof && !packet_have_data_to_write() &&
+                   buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) {
                        if (!channel_still_open())
                                break;
                        if (!waiting_termination) {
@@ -675,13 +664,10 @@ server_loop2(void)
                if (packet_not_very_much_data_to_write())
                        channel_output_poll();
                wait_until_can_do_something(&readset, &writeset, 0);
-               if (child_terminated && child_has_selected) {
-                       /* XXX: race - assumes only one child has terminated */
+               if (child_terminated) {
                        while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
                                session_close_by_pid(pid, status);
                        child_terminated = 0;
-                       child_has_selected = 0;
-                       signal(SIGCHLD, sigchld_handler2);
                }
                channel_after_select(&readset, &writeset);
                process_input(&readset);
@@ -737,10 +723,10 @@ server_input_window_size(int type, int plen, void *ctxt)
                pty_change_window_size(fdin, row, col, xpixel, ypixel);
 }
 
-int
-input_direct_tcpip(void)
+Channel *
+server_request_direct_tcpip(char *ctype)
 {
-       int sock;
+       int sock, newch;
        char *target, *originator;
        int target_port, originator_port;
 
@@ -750,23 +736,52 @@ input_direct_tcpip(void)
        originator_port = packet_get_int();
        packet_done();
 
-       debug("open direct-tcpip: from %s port %d to %s port %d",
+       debug("server_request_direct_tcpip: originator %s port %d, target %s port %d",
           originator, originator_port, target, target_port);
 
        /* XXX check permission */
        if (no_port_forwarding_flag || !options.allow_tcp_forwarding) {
                xfree(target);
                xfree(originator);
-               return -1;
+               return NULL;
        }
        sock = channel_connect_to(target, target_port);
        xfree(target);
        xfree(originator);
        if (sock < 0)
-               return -1;
-       return channel_new("direct-tcpip", SSH_CHANNEL_OPEN,
+               return NULL;
+       newch = channel_new(ctype, SSH_CHANNEL_OPEN,
            sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT,
-           CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("direct-tcpip"));
+           CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("direct-tcpip"), 1);
+       return (newch >= 0) ? channel_lookup(newch) : NULL;
+}
+
+Channel *
+server_request_session(char *ctype)
+{
+       int newch;
+
+       debug("input_session_request");
+       packet_done();
+       /*
+        * A server session has no fd to read or write until a
+        * CHANNEL_REQUEST for a shell is made, so we set the type to
+        * SSH_CHANNEL_LARVAL.  Additionally, a callback for handling all
+        * CHANNEL_REQUEST messages is registered.
+        */
+       newch = channel_new(ctype, SSH_CHANNEL_LARVAL,
+           -1, -1, -1, 0, CHAN_SES_PACKET_DEFAULT,
+           0, xstrdup("server-session"), 1);
+       if (session_open(newch) == 1) {
+               channel_register_callback(newch, SSH2_MSG_CHANNEL_REQUEST,
+                   session_input_channel_req, (void *)0);
+               channel_register_cleanup(newch, session_close_by_channel);
+               return channel_lookup(newch);
+       } else {
+               debug("session open failed, free channel %d", newch);
+               channel_free(newch);
+       }
+       return NULL;
 }
 
 void
@@ -774,7 +789,6 @@ server_input_channel_open(int type, int plen, void *ctxt)
 {
        Channel *c = NULL;
        char *ctype;
-       int id;
        unsigned int len;
        int rchan;
        int rmaxpack;
@@ -789,34 +803,12 @@ server_input_channel_open(int type, int plen, void *ctxt)
            ctype, rchan, rwindow, rmaxpack);
 
        if (strcmp(ctype, "session") == 0) {
-               debug("open session");
-               packet_done();
-               /*
-                * A server session has no fd to read or write
-                * until a CHANNEL_REQUEST for a shell is made,
-                * so we set the type to SSH_CHANNEL_LARVAL.
-                * Additionally, a callback for handling all
-                * CHANNEL_REQUEST messages is registered.
-                */
-               id = channel_new(ctype, SSH_CHANNEL_LARVAL,
-                   -1, -1, -1, 0, CHAN_SES_PACKET_DEFAULT,
-                   0, xstrdup("server-session"));
-               if (session_open(id) == 1) {
-                       channel_register_callback(id, SSH2_MSG_CHANNEL_REQUEST,
-                           session_input_channel_req, (void *)0);
-                       channel_register_cleanup(id, session_close_by_channel);
-                       c = channel_lookup(id);
-               } else {
-                       debug("session open failed, free channel %d", id);
-                       channel_free(id);
-               }
+               c = server_request_session(ctype);
        } else if (strcmp(ctype, "direct-tcpip") == 0) {
-               id = input_direct_tcpip();
-               if (id >= 0)
-                       c = channel_lookup(id);
+               c = server_request_direct_tcpip(ctype);
        }
        if (c != NULL) {
-               debug("confirm %s", ctype);
+               debug("server_input_channel_open: confirm %s", ctype);
                c->remote_id = rchan;
                c->remote_window = rwindow;
                c->remote_maxpacket = rmaxpack;
@@ -828,7 +820,7 @@ server_input_channel_open(int type, int plen, void *ctxt)
                packet_put_int(c->local_maxpacket);
                packet_send();
        } else {
-               debug("failure %s", ctype);
+               debug("server_input_channel_open: failure %s", ctype);
                packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
                packet_put_int(rchan);
                packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
@@ -839,6 +831,56 @@ server_input_channel_open(int type, int plen, void *ctxt)
        xfree(ctype);
 }
 
+void 
+server_input_global_request(int type, int plen, void *ctxt)
+{
+       char *rtype;
+       int want_reply;
+       int success = 0;
+
+       rtype = packet_get_string(NULL);
+       want_reply = packet_get_char();
+       debug("server_input_global_request: rtype %s want_reply %d", rtype, want_reply);
+       
+       if (strcmp(rtype, "tcpip-forward") == 0) {
+               struct passwd *pw;
+               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 */
+               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)) {
+                       success = 0;
+                       packet_send_debug("Server has disabled port forwarding.");
+               } else {
+                       /* Start listening on the port */
+                       channel_request_forwarding(
+                           listen_address, listen_port,
+                           /*unspec host_to_connect*/ "<unspec host>",
+                           /*unspec port_to_connect*/ 0,
+                           options.gateway_ports, /*remote*/ 1);
+                       success = 1;
+               }
+               xfree(listen_address);
+       }
+       if (want_reply) {
+               packet_start(success ?
+                   SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
+               packet_send();
+               packet_write_wait();
+       }
+       xfree(rtype);
+}
+
 void
 server_init_dispatch_20()
 {
@@ -853,6 +895,7 @@ server_init_dispatch_20()
        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_WINDOW_ADJUST, &channel_input_window_adjust);
+       dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request);
 }
 void
 server_init_dispatch_13()
This page took 0.522004 seconds and 4 git commands to generate.