]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
upstream: convert serverloop.c to new packet API
authordjm@openbsd.org <djm@openbsd.org>
Sat, 19 Jan 2019 21:40:48 +0000 (21:40 +0000)
committerDamien Miller <djm@mindrot.org>
Sat, 19 Jan 2019 22:45:17 +0000 (09:45 +1100)
with & ok markus@

OpenBSD-Commit-ID: c92dd19b55457541478f95c0d6b318426d86d885

serverloop.c

index e0c26bbbc394467916096b6e19411e4c617f8da2..c60758e8862540941ce7ca4b062b95f84d75719a 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: serverloop.c,v 1.210 2019/01/19 21:31:32 djm Exp $ */
+/* $OpenBSD: serverloop.c,v 1.211 2019/01/19 21:40:48 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -49,6 +49,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <pwd.h>
+#include <limits.h>
 #include <signal.h>
 #include <string.h>
 #include <termios.h>
@@ -78,9 +79,6 @@
 #include "serverloop.h"
 #include "ssherr.h"
 
-#include "opacket.h" /* XXX */
-extern struct ssh *active_state; /* XXX */
-
 extern ServerOptions options;
 
 /* XXX */
@@ -101,7 +99,7 @@ static volatile sig_atomic_t child_terminated = 0;   /* The child has terminated.
 static volatile sig_atomic_t received_sigterm = 0;
 
 /* prototypes */
-static void server_init_dispatch(void);
+static void server_init_dispatch(struct ssh *);
 
 /* requested tunnel forwarding interface(s), shared with session.c */
 char *tun_fwd_ifnames = NULL;
@@ -182,11 +180,12 @@ sigterm_handler(int sig)
 static void
 client_alive_check(struct ssh *ssh)
 {
-       int channel_id;
        char remote_id[512];
+       int r, channel_id;
 
        /* timeout, check to see how many we have had */
-       if (packet_inc_alive_timeouts() > options.client_alive_count_max) {
+       if (ssh_packet_inc_alive_timeouts(ssh) >
+           options.client_alive_count_max) {
                sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
                logit("Timeout, client not responding from %s", remote_id);
                cleanup_exit(255);
@@ -197,14 +196,17 @@ client_alive_check(struct ssh *ssh)
         * we should get back a failure
         */
        if ((channel_id = channel_find_open(ssh)) == -1) {
-               packet_start(SSH2_MSG_GLOBAL_REQUEST);
-               packet_put_cstring("keepalive@openssh.com");
-               packet_put_char(1);     /* boolean: want reply */
+               if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
+                   (r = sshpkt_put_cstring(ssh, "keepalive@openssh.com"))
+                   != 0 ||
+                   (r = sshpkt_put_u8(ssh, 1)) != 0) /* boolean: want reply */
+                       fatal("%s: %s", __func__, ssh_err(r));
        } else {
                channel_request_start(ssh, channel_id,
                    "keepalive@openssh.com", 1);
        }
-       packet_send();
+       if ((r = sshpkt_send(ssh)) != 0)
+               fatal("%s: %s", __func__, ssh_err(r));
 }
 
 /*
@@ -261,14 +263,14 @@ wait_until_can_do_something(struct ssh *ssh,
         * If we have buffered packet data going to the client, mark that
         * descriptor.
         */
-       if (packet_have_data_to_write())
+       if (ssh_packet_have_data_to_write(ssh))
                FD_SET(connection_out, *writesetp);
 
        /*
         * If child has terminated and there is enough buffer space to read
         * from it, then read as much as is available and exit.
         */
-       if (child_terminated && packet_not_very_much_data_to_write())
+       if (child_terminated && ssh_packet_not_very_much_data_to_write(ssh))
                if (max_time_ms == 0 || client_alive_scheduled)
                        max_time_ms = 100;
 
@@ -312,7 +314,7 @@ wait_until_can_do_something(struct ssh *ssh,
 static int
 process_input(struct ssh *ssh, fd_set *readset, int connection_in)
 {
-       int len;
+       int r, len;
        char buf[16384];
 
        /* Read and buffer any input data from the client. */
@@ -333,7 +335,10 @@ process_input(struct ssh *ssh, fd_set *readset, int connection_in)
                        }
                } else {
                        /* Buffer any received data. */
-                       packet_process_incoming(buf, len);
+                       if ((r = ssh_packet_process_incoming(ssh, buf, len))
+                           != 0)
+                               fatal("%s: ssh_packet_process_incoming: %s",
+                                   __func__, ssh_err(r));
                }
        }
        return 0;
@@ -343,11 +348,16 @@ process_input(struct ssh *ssh, fd_set *readset, int connection_in)
  * Sends data from internal buffers to client program stdin.
  */
 static void
-process_output(fd_set *writeset, int connection_out)
+process_output(struct ssh *ssh, fd_set *writeset, int connection_out)
 {
+       int r;
+
        /* Send any buffered packet data to the client. */
-       if (FD_ISSET(connection_out, writeset))
-               packet_write_poll();
+       if (FD_ISSET(connection_out, writeset)) {
+               if ((r = ssh_packet_write_poll(ssh)) != 0)
+                       fatal("%s: ssh_packet_write_poll: %s",
+                           __func__, ssh_err(r));
+       }
 }
 
 static void
@@ -390,8 +400,8 @@ server_loop2(struct ssh *ssh, Authctxt *authctxt)
 
        signal(SIGCHLD, sigchld_handler);
        child_terminated = 0;
-       connection_in = packet_get_connection_in();
-       connection_out = packet_get_connection_out();
+       connection_in = ssh_packet_get_connection_in(ssh);
+       connection_out = ssh_packet_get_connection_out(ssh);
 
        if (!use_privsep) {
                signal(SIGTERM, sigterm_handler);
@@ -404,18 +414,21 @@ server_loop2(struct ssh *ssh, Authctxt *authctxt)
        max_fd = MAXIMUM(connection_in, connection_out);
        max_fd = MAXIMUM(max_fd, notify_pipe[0]);
 
-       server_init_dispatch();
+       server_init_dispatch(ssh);
 
        for (;;) {
                process_buffered_input_packets(ssh);
 
                if (!ssh_packet_is_rekeying(ssh) &&
-                   packet_not_very_much_data_to_write())
+                   ssh_packet_not_very_much_data_to_write(ssh))
                        channel_output_poll(ssh);
-               if (options.rekey_interval > 0 && !ssh_packet_is_rekeying(ssh))
-                       rekey_timeout_ms = packet_get_rekey_timeout() * 1000;
-               else
+               if (options.rekey_interval > 0 &&
+                   !ssh_packet_is_rekeying(ssh)) {
+                       rekey_timeout_ms = ssh_packet_get_rekey_timeout(ssh) *
+                           1000;
+               } else {
                        rekey_timeout_ms = 0;
+               }
 
                wait_until_can_do_something(ssh, connection_in, connection_out,
                    &readset, &writeset, &max_fd, &nalloc, rekey_timeout_ms);
@@ -431,7 +444,7 @@ server_loop2(struct ssh *ssh, Authctxt *authctxt)
                        channel_after_select(ssh, readset, writeset);
                if (process_input(ssh, readset, connection_in) < 0)
                        break;
-               process_output(writeset, connection_out);
+               process_output(ssh, writeset, connection_out);
        }
        collect_children(ssh);
 
@@ -454,7 +467,7 @@ server_input_keep_alive(int type, u_int32_t seq, struct ssh *ssh)
         * even if this was generated by something other than
         * the bogus CHANNEL_REQUEST we send for keepalives.
         */
-       packet_set_alive_timeouts(0);
+       ssh_packet_set_alive_timeouts(ssh, 0);
        return 0;
 }
 
@@ -462,16 +475,28 @@ static Channel *
 server_request_direct_tcpip(struct ssh *ssh, int *reason, const char **errmsg)
 {
        Channel *c = NULL;
-       char *target, *originator;
-       u_short target_port, originator_port;
-
-       target = packet_get_string(NULL);
-       target_port = packet_get_int();
-       originator = packet_get_string(NULL);
-       originator_port = packet_get_int();
-       packet_check_eom();
+       char *target = NULL, *originator = NULL;
+       u_int target_port = 0, originator_port = 0;
+       int r;
+
+       if ((r = sshpkt_get_cstring(ssh, &target, NULL)) != 0 ||
+           (r = sshpkt_get_u32(ssh, &target_port)) != 0 ||
+           (r = sshpkt_get_cstring(ssh, &originator, NULL)) != 0 ||
+           (r = sshpkt_get_u32(ssh, &originator_port)) != 0 ||
+           (r = sshpkt_get_end(ssh)) != 0)
+               sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
+       if (target_port > 0xFFFF) {
+               error("%s: invalid target port", __func__);
+               *reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED;
+               goto out;
+       }
+       if (originator_port > 0xFFFF) {
+               error("%s: invalid originator port", __func__);
+               *reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED;
+               goto out;
+       }
 
-       debug("%s: originator %s port %d, target %s port %d", __func__,
+       debug("%s: originator %s port %u, target %s port %u", __func__,
            originator, originator_port, target, target_port);
 
        /* XXX fine grained permissions */
@@ -488,9 +513,9 @@ server_request_direct_tcpip(struct ssh *ssh, int *reason, const char **errmsg)
                        *reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED;
        }
 
+ out:
        free(originator);
        free(target);
-
        return c;
 }
 
@@ -498,17 +523,23 @@ static Channel *
 server_request_direct_streamlocal(struct ssh *ssh)
 {
        Channel *c = NULL;
-       char *target, *originator;
-       u_short originator_port;
+       char *target = NULL, *originator = NULL;
+       u_int originator_port = 0;
        struct passwd *pw = the_authctxt->pw;
+       int r;
 
        if (pw == NULL || !the_authctxt->valid)
                fatal("%s: no/invalid user", __func__);
 
-       target = packet_get_string(NULL);
-       originator = packet_get_string(NULL);
-       originator_port = packet_get_int();
-       packet_check_eom();
+       if ((r = sshpkt_get_cstring(ssh, &target, NULL)) != 0 ||
+           (r = sshpkt_get_cstring(ssh, &originator, NULL)) != 0 ||
+           (r = sshpkt_get_u32(ssh, &originator_port)) != 0 ||
+           (r = sshpkt_get_end(ssh)) != 0)
+               sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
+       if (originator_port > 0xFFFF) {
+               error("%s: invalid originator port", __func__);
+               goto out;
+       }
 
        debug("%s: originator %s port %d, target %s", __func__,
            originator, originator_port, target);
@@ -525,9 +556,9 @@ server_request_direct_streamlocal(struct ssh *ssh)
                    originator, originator_port, target);
        }
 
+out:
        free(originator);
        free(target);
-
        return c;
 }
 
@@ -535,27 +566,35 @@ static Channel *
 server_request_tun(struct ssh *ssh)
 {
        Channel *c = NULL;
-       int mode, tun, sock;
+       u_int mode, tun;
+       int r, sock;
        char *tmp, *ifname = NULL;
 
-       mode = packet_get_int();
+       if ((r = sshpkt_get_u32(ssh, &mode)) != 0)
+               sshpkt_fatal(ssh, r, "%s: parse mode", __func__);
        switch (mode) {
        case SSH_TUNMODE_POINTOPOINT:
        case SSH_TUNMODE_ETHERNET:
                break;
        default:
-               packet_send_debug("Unsupported tunnel device mode.");
+               ssh_packet_send_debug(ssh, "Unsupported tunnel device mode.");
                return NULL;
        }
        if ((options.permit_tun & mode) == 0) {
-               packet_send_debug("Server has rejected tunnel device "
+               ssh_packet_send_debug(ssh, "Server has rejected tunnel device "
                    "forwarding");
                return NULL;
        }
 
-       tun = packet_get_int();
+       if ((r = sshpkt_get_u32(ssh, &tun)) != 0)
+               sshpkt_fatal(ssh, r, "%s: parse device", __func__);
+       if (tun > INT_MAX) {
+               debug("%s: invalid tun", __func__);
+               goto done;
+       }
        if (auth_opts->force_tun_device != -1) {
-               if (tun != SSH_TUNID_ANY && auth_opts->force_tun_device != tun)
+               if (tun != SSH_TUNID_ANY &&
+                   auth_opts->force_tun_device != (int)tun)
                        goto done;
                tun = auth_opts->force_tun_device;
        }
@@ -588,7 +627,7 @@ server_request_tun(struct ssh *ssh)
 
  done:
        if (c == NULL)
-               packet_send_debug("Failed to open the tunnel device.");
+               ssh_packet_send_debug(ssh, "Failed to open the tunnel device.");
        return c;
 }
 
@@ -596,13 +635,15 @@ static Channel *
 server_request_session(struct ssh *ssh)
 {
        Channel *c;
+       int r;
 
        debug("input_session_request");
-       packet_check_eom();
+       if ((r = sshpkt_get_end(ssh)) != 0)
+               sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
 
        if (no_more_sessions) {
-               packet_disconnect("Possible attack: attempt to open a session "
-                   "after additional sessions disabled");
+               sshpkt_disconnect(ssh, "Possible attack: attempt to open a "
+                   "session after additional sessions disabled");
        }
 
        /*
@@ -627,20 +668,22 @@ static int
 server_input_channel_open(int type, u_int32_t seq, struct ssh *ssh)
 {
        Channel *c = NULL;
-       char *ctype;
+       char *ctype = NULL;
        const char *errmsg = NULL;
-       int rchan, reason = SSH2_OPEN_CONNECT_FAILED;
-       u_int rmaxpack, rwindow, len;
-
-       ctype = packet_get_string(&len);
-       rchan = packet_get_int();
-       rwindow = packet_get_int();
-       rmaxpack = packet_get_int();
-
-       debug("%s: ctype %s rchan %d win %d max %d", __func__,
+       int r, reason = SSH2_OPEN_CONNECT_FAILED;
+       u_int rchan = 0, rmaxpack = 0, rwindow = 0;
+
+       if ((r = sshpkt_get_cstring(ssh, &ctype, NULL)) != 0 ||
+           (r = sshpkt_get_u32(ssh, &rchan)) != 0 ||
+           (r = sshpkt_get_u32(ssh, &rwindow)) != 0 ||
+           (r = sshpkt_get_u32(ssh, &rmaxpack)) != 0)
+               sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
+       debug("%s: ctype %s rchan %u win %u max %u", __func__,
            ctype, rchan, rwindow, rmaxpack);
 
-       if (strcmp(ctype, "session") == 0) {
+       if (rchan > INT_MAX) {
+               error("%s: invalid remote channel ID", __func__);
+       } else if (strcmp(ctype, "session") == 0) {
                c = server_request_session(ssh);
        } else if (strcmp(ctype, "direct-tcpip") == 0) {
                c = server_request_direct_tcpip(ssh, &reason, &errmsg);
@@ -651,26 +694,32 @@ server_input_channel_open(int type, u_int32_t seq, struct ssh *ssh)
        }
        if (c != NULL) {
                debug("%s: confirm %s", __func__, ctype);
-               c->remote_id = rchan;
+               c->remote_id = (int)rchan;
                c->have_remote_id = 1;
                c->remote_window = rwindow;
                c->remote_maxpacket = rmaxpack;
                if (c->type != SSH_CHANNEL_CONNECTING) {
-                       packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
-                       packet_put_int(c->remote_id);
-                       packet_put_int(c->self);
-                       packet_put_int(c->local_window);
-                       packet_put_int(c->local_maxpacket);
-                       packet_send();
+                       if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION)) != 0 ||
+                           (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
+                           (r = sshpkt_put_u32(ssh, c->self)) != 0 ||
+                           (r = sshpkt_put_u32(ssh, c->local_window)) != 0 ||
+                           (r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0 ||
+                           (r = sshpkt_send(ssh)) != 0) {
+                               sshpkt_fatal(ssh, r,
+                                   "%s: send open confirm", __func__);
+                       }
                }
        } else {
                debug("%s: failure %s", __func__, ctype);
-               packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
-               packet_put_int(rchan);
-               packet_put_int(reason);
-               packet_put_cstring(errmsg ? errmsg : "open failed");
-               packet_put_cstring("");
-               packet_send();
+               if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN_FAILURE)) != 0 ||
+                   (r = sshpkt_put_u32(ssh, rchan)) != 0 ||
+                   (r = sshpkt_put_u32(ssh, reason)) != 0 ||
+                   (r = sshpkt_put_cstring(ssh, errmsg ? errmsg : "open failed")) != 0 ||
+                   (r = sshpkt_put_cstring(ssh, "")) != 0 ||
+                   (r = sshpkt_send(ssh)) != 0) {
+                       sshpkt_fatal(ssh, r,
+                           "%s: send open failure", __func__);
+               }
        }
        free(ctype);
        return 0;
@@ -757,65 +806,66 @@ server_input_hostkeys_prove(struct ssh *ssh, struct sshbuf **respp)
 static int
 server_input_global_request(int type, u_int32_t seq, struct ssh *ssh)
 {
-       char *rtype;
-       int want_reply;
+       char *rtype = NULL;
+       u_char want_reply = 0;
        int r, success = 0, allocated_listen_port = 0;
+       u_int port = 0;
        struct sshbuf *resp = NULL;
        struct passwd *pw = the_authctxt->pw;
+       struct Forward fwd;
 
+       memset(&fwd, 0, sizeof(fwd));
        if (pw == NULL || !the_authctxt->valid)
                fatal("%s: no/invalid user", __func__);
 
-       rtype = packet_get_string(NULL);
-       want_reply = packet_get_char();
+       if ((r = sshpkt_get_cstring(ssh, &rtype, NULL)) != 0 ||
+           (r = sshpkt_get_u8(ssh, &want_reply)) != 0)
+               sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
        debug("%s: rtype %s want_reply %d", __func__, rtype, want_reply);
 
        /* -R style forwarding */
        if (strcmp(rtype, "tcpip-forward") == 0) {
-               struct Forward fwd;
-
-               memset(&fwd, 0, sizeof(fwd));
-               fwd.listen_host = packet_get_string(NULL);
-               fwd.listen_port = (u_short)packet_get_int();
-               debug("%s: tcpip-forward listen %s port %d", __func__,
-                   fwd.listen_host, fwd.listen_port);
-
+               if ((r = sshpkt_get_cstring(ssh, &fwd.listen_host, NULL)) != 0 ||
+                   (r = sshpkt_get_u32(ssh, &port)) != 0)
+                       sshpkt_fatal(ssh, r, "%s: parse tcpip-forward", __func__);
+               debug("%s: tcpip-forward listen %s port %u", __func__,
+                   fwd.listen_host, port);
+               if (port <= INT_MAX)
+                       fwd.listen_port = (int)port;
                /* check permissions */
-               if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0 ||
+               if (port > INT_MAX ||
+                   (options.allow_tcp_forwarding & FORWARD_REMOTE) == 0 ||
                    !auth_opts->permit_port_forwarding_flag ||
                    options.disable_forwarding ||
                    (!want_reply && fwd.listen_port == 0) ||
                    (fwd.listen_port != 0 &&
                     !bind_permitted(fwd.listen_port, pw->pw_uid))) {
                        success = 0;
-                       packet_send_debug("Server has disabled port forwarding.");
+                       ssh_packet_send_debug(ssh, "Server has disabled port forwarding.");
                } else {
                        /* Start listening on the port */
                        success = channel_setup_remote_fwd_listener(ssh, &fwd,
                            &allocated_listen_port, &options.fwd_opts);
                }
-               free(fwd.listen_host);
                if ((resp = sshbuf_new()) == NULL)
                        fatal("%s: sshbuf_new", __func__);
                if (allocated_listen_port != 0 &&
                    (r = sshbuf_put_u32(resp, allocated_listen_port)) != 0)
                        fatal("%s: sshbuf_put_u32: %s", __func__, ssh_err(r));
        } else if (strcmp(rtype, "cancel-tcpip-forward") == 0) {
-               struct Forward fwd;
+               if ((r = sshpkt_get_cstring(ssh, &fwd.listen_host, NULL)) != 0 ||
+                   (r = sshpkt_get_u32(ssh, &port)) != 0)
+                       sshpkt_fatal(ssh, r, "%s: parse cancel-tcpip-forward", __func__);
 
-               memset(&fwd, 0, sizeof(fwd));
-               fwd.listen_host = packet_get_string(NULL);
-               fwd.listen_port = (u_short)packet_get_int();
                debug("%s: cancel-tcpip-forward addr %s port %d", __func__,
-                   fwd.listen_host, fwd.listen_port);
-
-               success = channel_cancel_rport_listener(ssh, &fwd);
-               free(fwd.listen_host);
+                   fwd.listen_host, port);
+               if (port <= INT_MAX) {
+                       fwd.listen_port = (int)port;
+                       success = channel_cancel_rport_listener(ssh, &fwd);
+               }
        } else if (strcmp(rtype, "streamlocal-forward@openssh.com") == 0) {
-               struct Forward fwd;
-
-               memset(&fwd, 0, sizeof(fwd));
-               fwd.listen_path = packet_get_string(NULL);
+               if ((r = sshpkt_get_cstring(ssh, &fwd.listen_path, NULL)) != 0)
+                       sshpkt_fatal(ssh, r, "%s: parse streamlocal-forward@openssh.com", __func__);
                debug("%s: streamlocal-forward listen path %s", __func__,
                    fwd.listen_path);
 
@@ -825,39 +875,37 @@ server_input_global_request(int type, u_int32_t seq, struct ssh *ssh)
                    options.disable_forwarding ||
                    (pw->pw_uid != 0 && !use_privsep)) {
                        success = 0;
-                       packet_send_debug("Server has disabled "
+                       ssh_packet_send_debug(ssh, "Server has disabled "
                            "streamlocal forwarding.");
                } else {
                        /* Start listening on the socket */
                        success = channel_setup_remote_fwd_listener(ssh,
                            &fwd, NULL, &options.fwd_opts);
                }
-               free(fwd.listen_path);
        } else if (strcmp(rtype, "cancel-streamlocal-forward@openssh.com") == 0) {
-               struct Forward fwd;
-
-               memset(&fwd, 0, sizeof(fwd));
-               fwd.listen_path = packet_get_string(NULL);
+               if ((r = sshpkt_get_cstring(ssh, &fwd.listen_path, NULL)) != 0)
+                       sshpkt_fatal(ssh, r, "%s: parse cancel-streamlocal-forward@openssh.com", __func__);
                debug("%s: cancel-streamlocal-forward path %s", __func__,
                    fwd.listen_path);
 
                success = channel_cancel_rport_listener(ssh, &fwd);
-               free(fwd.listen_path);
        } else if (strcmp(rtype, "no-more-sessions@openssh.com") == 0) {
                no_more_sessions = 1;
                success = 1;
        } else if (strcmp(rtype, "hostkeys-prove-00@openssh.com") == 0) {
                success = server_input_hostkeys_prove(ssh, &resp);
        }
+       /* XXX sshpkt_get_end() */
        if (want_reply) {
-               packet_start(success ?
-                   SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
-               if (success && resp != NULL)
-                       ssh_packet_put_raw(ssh, sshbuf_ptr(resp),
-                           sshbuf_len(resp));
-               packet_send();
-               packet_write_wait();
+               if ((r = sshpkt_start(ssh, success ?
+                   SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE)) != 0 ||
+                   (success && resp != NULL && (r = sshpkt_putb(ssh, resp)) != 0) ||
+                   (r = sshpkt_send(ssh)) != 0 ||
+                   (r = ssh_packet_write_wait(ssh)) != 0)
+                       sshpkt_fatal(ssh, r, "%s: send reply", __func__);
        }
+       free(fwd.listen_host);
+       free(fwd.listen_path);
        free(rtype);
        sshbuf_free(resp);
        return 0;
@@ -867,58 +915,62 @@ static int
 server_input_channel_req(int type, u_int32_t seq, struct ssh *ssh)
 {
        Channel *c;
-       int id, reply, success = 0;
-       char *rtype;
+       int r, success = 0;
+       char *rtype = NULL;
+       u_char want_reply = 0;
+       u_int id = 0;
 
-       id = packet_get_int();
-       rtype = packet_get_string(NULL);
-       reply = packet_get_char();
+       if ((r = sshpkt_get_u32(ssh, &id)) != 0 ||
+           (r = sshpkt_get_cstring(ssh, &rtype, NULL)) != 0 ||
+           (r = sshpkt_get_u8(ssh, &want_reply)) != 0)
+               sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
 
-       debug("server_input_channel_req: channel %d request %s reply %d",
-           id, rtype, reply);
+       debug("server_input_channel_req: channel %u request %s reply %d",
+           id, rtype, want_reply);
 
-       if ((c = channel_lookup(ssh, id)) == NULL)
-               packet_disconnect("server_input_channel_req: "
-                   "unknown channel %d", id);
+       if (id >= INT_MAX || (c = channel_lookup(ssh, (int)id)) == NULL)
+               sshpkt_disconnect(ssh, "%s: unknown channel %d", __func__, id);
        if (!strcmp(rtype, "eow@openssh.com")) {
-               packet_check_eom();
+               if ((r = sshpkt_get_end(ssh)) != 0)
+                       sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
                chan_rcvd_eow(ssh, c);
        } else if ((c->type == SSH_CHANNEL_LARVAL ||
            c->type == SSH_CHANNEL_OPEN) && strcmp(c->ctype, "session") == 0)
                success = session_input_channel_req(ssh, c, rtype);
-       if (reply && !(c->flags & CHAN_CLOSE_SENT)) {
+       if (want_reply && !(c->flags & CHAN_CLOSE_SENT)) {
                if (!c->have_remote_id)
                        fatal("%s: channel %d: no remote_id",
                            __func__, c->self);
-               packet_start(success ?
-                   SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
-               packet_put_int(c->remote_id);
-               packet_send();
+               if ((r = sshpkt_start(ssh, success ?
+                   SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE)) != 0 ||
+                   (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
+                   (r = sshpkt_send(ssh)) != 0)
+                       sshpkt_fatal(ssh, r, "%s: send reply", __func__);
        }
        free(rtype);
        return 0;
 }
 
 static void
-server_init_dispatch(void)
+server_init_dispatch(struct ssh *ssh)
 {
        debug("server_init_dispatch");
-       dispatch_init(&dispatch_protocol_error);
-       dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose);
-       dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data);
-       dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof);
-       dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data);
-       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, &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);
+       ssh_dispatch_init(ssh, &dispatch_protocol_error);
+       ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose);
+       ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_DATA, &channel_input_data);
+       ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_EOF, &channel_input_ieof);
+       ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data);
+       ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_OPEN, &server_input_channel_open);
+       ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
+       ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
+       ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_REQUEST, &server_input_channel_req);
+       ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
+       ssh_dispatch_set(ssh, SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request);
        /* client_alive */
-       dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &server_input_keep_alive);
-       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);
+       ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_SUCCESS, &server_input_keep_alive);
+       ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_FAILURE, &server_input_keep_alive);
+       ssh_dispatch_set(ssh, SSH2_MSG_REQUEST_SUCCESS, &server_input_keep_alive);
+       ssh_dispatch_set(ssh, SSH2_MSG_REQUEST_FAILURE, &server_input_keep_alive);
        /* rekeying */
-       dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
+       ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
 }