Skip to content
Snippets Groups Projects
Select Git revision
  • a0b72cf12ebcf1d4fc008a8487b97b863e3987e6
  • master default
  • wip-slh-dsa-sha2-128s
  • master-updates
  • release-3.10-fixes
  • getopt-prototype
  • fix-bcrypt-warning
  • refactor-hmac
  • wip-use-alignas
  • trim-sha3-context
  • fix-gitlab-ci
  • check-fat-emulate
  • delete-digest_func-size
  • slh-dsa-shake-128f-nettle
  • slh-dsa-shake-128s-nettle
  • slh-dsa-shake-128s
  • delete-openpgp
  • ppc64-sha512
  • delete-md5-compat
  • cleanup-hmac-tests
  • ppc64-sha256
  • nettle_3.10.2_release_20250626
  • nettle_3.10.1_release_20241230
  • nettle_3.10_release_20240616
  • nettle_3.10rc2
  • nettle_3.10rc1
  • nettle_3.9.1_release_20230601
  • nettle_3.9_release_20230514
  • nettle_3.8.1_release_20220727
  • nettle_3.8_release_20220602
  • nettle_3.7.3_release_20210606
  • nettle_3.7.2_release_20210321
  • nettle_3.7.1_release_20210217
  • nettle_3.7_release_20210104
  • nettle_3.7rc1
  • nettle_3.6_release_20200429
  • nettle_3.6rc3
  • nettle_3.6rc2
  • nettle_3.6rc1
  • nettle_3.5.1_release_20190627
  • nettle_3.5_release_20190626
41 results

der-iterator.c

  • tcpforward_commands.c 14.00 KiB
    /* tcpforward_commands.c
     *
     * $Id$
     */
    
    /* lsh, an implementation of the ssh protocol
     *
     * Copyright (C) 1998 Balázs Scheidler, Niels Möller
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License as
     * published by the Free Software Foundation; either version 2 of the
     * License, or (at your option) any later version.
     *
     * This program is distributed in the hope that it will be useful, but
     * WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
     * General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this program; if not, write to the Free Software
     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     */
    
    #include "tcpforward_commands.h"
    
    #include "atoms.h"
    #include "channel_commands.h"
    #include "connection_commands.h"
    #include "format.h"
    #include "io_commands.h"
    #include "ssh.h"
    #include "werror.h"
    #include "xalloc.h"
    
    #include <assert.h>
    
    /* Forward declarations */
    
    extern struct command_2 open_direct_tcpip;
    extern struct command_2 remote_listen_command;
    extern struct command_2 open_forwarded_tcpip;
    extern struct command tcpip_start_io;
    extern struct command tcpip_connect_io;
    
    struct install_info install_direct_tcpip_handler;
    struct install_info install_forwarded_tcpip_handler;
    
    /* FIXME: Should be static? */
    struct command make_direct_tcpip_handler;
    
    struct install_info install_tcpip_forward_handler;
    
    /* FIXME: Should be static? */
    struct command make_tcpip_forward_handler;
    
    #define OPEN_DIRECT_TCPIP (&open_direct_tcpip.super.super)
    #define REMOTE_LISTEN (&remote_listen_command.super.super)
    #define TCPIP_START_IO (&tcpip_start_io.super)
    #define TCPIP_CONNECT_IO (&tcpip_connect_io.super)
    #define OPEN_FORWARDED_TCPIP (&open_forwarded_tcpip.super.super)
    #define DIRECT_TCPIP_HANDLER (&make_direct_tcpip_handler.super)
    #define INSTALL_DIRECT_TCPIP (&install_direct_tcpip_handler.super.super.super)
    
    static struct catch_report_collect catch_channel_open;
    #define CATCH_CHANNEL_OPEN (&catch_channel_open.super.super)
    
    #include "tcpforward_commands.c.x"
    
    static struct report_exception_info open_tcpip_report =
    STATIC_REPORT_EXCEPTION_INFO(EXC_ALL, EXC_CHANNEL_OPEN, "Failed to open tcpip channel");
    
    static struct catch_report_collect catch_channel_open
    = STATIC_CATCH_REPORT(&open_tcpip_report);
    
    /* Takes a socket as argument, and returns a tcpip channel. Used by
     * the party receiving a open-tcp request, when a channel to the
     * target has been opened. */
    
    #define TCPIP_WINDOW_SIZE 10000
    
    /* NOTE: make_tcpip_channel adds the fd to the channel's resource list. */
    static void
    do_tcpip_connect_io(struct command *ignored UNUSED,
    		    struct lsh_object *x,
    		    struct command_continuation *c,
    		    struct exception_handler *e UNUSED)
    {
      CAST(listen_value, lv, x);
    
      assert(lv);
      assert(lv->fd);
      
      COMMAND_RETURN(c, make_tcpip_channel(lv->fd, TCPIP_WINDOW_SIZE));
    }
    
    struct command tcpip_connect_io = STATIC_COMMAND(do_tcpip_connect_io);
    
    /* Used by the party requesting tcp forwarding, i.e. when a socket is
     * already open, and we have asked the other end to forward it. Takes
     * a channel as argument, and connects it to the socket. Returns the
     * channel. */
    
    static void
    do_tcpip_start_io(struct command *s UNUSED, 
    		  struct lsh_object *x,
    		  struct command_continuation *c,
    		  struct exception_handler *e UNUSED)
    {
      CAST_SUBTYPE(ssh_channel, channel, x);
    
      assert(channel);
      
      tcpip_channel_start_io(channel);
    
      COMMAND_RETURN(c, channel);
    }
    
    struct command tcpip_start_io =
    { STATIC_HEADER, do_tcpip_start_io };
    
    
    /* Requesting the opening of a forwarded tcpip channel. */
    
    /* Used for both forwarded-tcpip and direct-tcpip. Takes a listen
     * value as argument, and returns a channel connected to some tcpip
     * port at the other end. */
    
    /* GABA:
       (class
         (name open_tcpip_command)
         (super channel_open_command)
         (vars
           ; ATOM_FORWARDED_TCPIP or ATOM_DIRECT_TCPIP
           (type . int)
    
           (initial_window . UINT32)
    
           ; For forwarded-tcpip, port is the port listened to.
           ; For direct-tcpip, port is the port to connect to.
           ; In both cases, it's a port used on the server end.
           (port object address_info)
           (peer object listen_value)))
    */
    
    static struct ssh_channel *
    new_tcpip_channel(struct channel_open_command *c,
    		  struct ssh_connection *connection,
    		  UINT32 local_channel_number,
    		  struct lsh_string **request)
    {
      CAST(open_tcpip_command, self, c);
      struct ssh_channel *channel;
    
      /* NOTE: All accepted fd:s must end up in this function, so it
       * should be ok to delay the REMEMBER call until here. It is done
       * by make_tcpip_channel. */
    
      debug("tcpforward_commands.c: new_tcpip_channel\n");
    
      channel = make_tcpip_channel(self->peer->fd, TCPIP_WINDOW_SIZE);
      channel->write = connection->write;
    
      *request = format_channel_open(self->type, local_channel_number,
    				 channel, 
    				 "%S%i%S%i",
    				 self->port->ip, self->port->port,
    				 self->peer->peer->ip, self->peer->peer->port);
      
      return channel;
    }
    
    static struct command *
    make_open_tcpip_command(int type, UINT32 initial_window,
    			struct address_info *port,
    			struct listen_value *peer)
    {
      NEW(open_tcpip_command, self);
    
      debug("tcpforward_commands.c: make_open_tcpip_command\n");
    
      self->super.super.call = do_channel_open_command;
      self->super.new_channel = new_tcpip_channel;
    
      self->type = type;
      self->initial_window = initial_window;
      
      self->port = port;
      self->peer = peer;
      
      return &self->super.super;
    }
    
    DEFINE_COMMAND2(open_forwarded_tcpip)
         (struct command_2 *s UNUSED,
          struct lsh_object *a1,
          struct lsh_object *a2,
          struct command_continuation *c,
          struct exception_handler *e UNUSED)
    {
      CAST(address_info, local, a1);
      CAST(listen_value, peer, a2);
      
      COMMAND_RETURN(c,
    		 make_open_tcpip_command(ATOM_FORWARDED_TCPIP,
    					 TCPIP_WINDOW_SIZE,
    					 local, peer));
    }
    
    DEFINE_COMMAND2(open_direct_tcpip)
         (struct command_2 *s UNUSED,
          struct lsh_object *a1,
          struct lsh_object *a2,
          struct command_continuation *c,
          struct exception_handler *e UNUSED)
    {
      CAST(address_info, local, a1);
      CAST(listen_value, peer, a2);
      
      COMMAND_RETURN(c,
    		 make_open_tcpip_command(ATOM_DIRECT_TCPIP,
    					 TCPIP_WINDOW_SIZE,
    					 local, peer));
    }
    
    
    /* Requesting remote forwarding of a port */
    
    /* GABA:
       (class
         (name remote_port_install_continuation)
         (super command_frame)
         (vars
           (port object remote_port)
           (callback object command)))
    */
    
    static void
    do_remote_port_install_continuation(struct command_continuation *s,
    				    struct lsh_object *x)
    {
      CAST(remote_port_install_continuation, self, s);
      CAST(ssh_connection, connection, x);
    
      assert(connection);
    
      debug("tcpforward_commands.c: do_remote_port_install_continuation, success.\n");
      self->port->callback = self->callback;
    
      COMMAND_RETURN(self->super.up, x);
    }
    
    static struct command_continuation *
    make_remote_port_install_continuation(struct remote_port *port,
    				      struct command *callback,
    				      struct command_continuation *c)
    {
      NEW(remote_port_install_continuation, self);
    
      debug("tcpforward_commands.c: make_remote_port_install_continuation\n");
    
      self->super.super.c = do_remote_port_install_continuation;
      self->super.up = c;
    
      self->port = port;
      self->callback = callback;
    
      return &self->super.super;
    }
    
    /* Listening on a remote port
     *
     * (remote_listen callback port connection)
     *
     * Returns a remote_port or NULL.
     * 
     * callback is invoked with a address_info peer as argument, and
     * should return a channel or NULL.
     */
    
    /* GABA:
       (class
         (name request_tcpip_forward_command)
         (super global_request_command)
         (vars
           ; Invoked when a forwarded_tcpip request is received.
           ; Called with the struct address_info *peer as argument.
           (callback object command)
           (port object address_info))) */
    
    static struct lsh_string *
    do_format_request_tcpip_forward(struct global_request_command *s,
    				struct ssh_connection *connection,
    				struct command_continuation **c)
    {
      CAST(request_tcpip_forward_command, self, s);
      struct remote_port *port;
      int want_reply;
    
      debug("tcpforward_commands.c: do_format_request_tcpip_forward\n");
    
      if (CONTINUATION_USED_P(*c))
        {
          /* FIXME: Use some exception handler to remove the port from the
           * list if the request fails. */
          port = make_remote_port(self->port, NULL);
          *c = make_remote_port_install_continuation(port, self->callback, *c);
          want_reply = 1;
        }
      else
        {
          port = make_remote_port(self->port, self->callback);
          want_reply = 0;
        }
      
      object_queue_add_tail(&connection->table->remote_ports,
    			&port->super.super);
      
      return format_global_request(ATOM_TCPIP_FORWARD, want_reply, "%S%i",
    			       self->port->ip, self->port->port);
    }
    
    
    DEFINE_COMMAND2(remote_listen_command)
         (struct command_2 *s UNUSED,
          struct lsh_object *a1,
          struct lsh_object *a2,
          struct command_continuation *c,
          struct exception_handler *e UNUSED)
    {
      trace("remote_listen_command\n");
    
      {
        CAST_SUBTYPE(command, callback, a1);
        CAST(address_info, port, a2);
        
        NEW(request_tcpip_forward_command, self);
        
        self->super.super.call = do_channel_global_command;
        self->super.format_request = do_format_request_tcpip_forward;
    
        self->callback = callback;
        self->port = port;
        
        COMMAND_RETURN(c, self);
      }
    }
    
    
    /* Cancel a remotely forwarded port.
     * FIXME: Not implemented */
    
    
    
    /* GABA:
       (expr
         (name forward_local_port)
         (params
           (backend object io_backend)
           (local object address_info)
           (target object address_info))
         (expr
           (lambda (connection)
             (connection_remember connection
               (listen_callback
    	     (lambda (peer)
    	       ;; Remembering is done by open_direct_tcpip
    	       ;; and new_tcpip_channel.
    	       (tcpip_start_io
    	         (catch_channel_open 
    		   (open_direct_tcpip target peer) connection)))
    	     backend
    	     local)))))
    */
    
    struct command *
    make_forward_local_port(struct io_backend *backend,
    			struct address_info *local,
    			struct address_info *target)
    {
      CAST_SUBTYPE(command, res,
    	       forward_local_port(backend, local, target));
    
      trace("tcpforward_commands.c: forward_local_port\n");
    
      return res;
    }
    
    /* GABA:
       (expr
         (name forward_remote_port)
         (params
           (connect object command)
           (remote object address_info))
         (expr
           (lambda (connection)
             (remote_listen (lambda (peer)
    	                  (tcpip_connect_io 
    			     ; NOTE: The use of prog1 is needed to
    			     ; delay the connect call until the
    			     ; (otherwise ignored) peer argument is
    			     ; available.  
    			     (connect (prog1 connection peer))))
    	                remote
    			connection))))
    */
    
    struct command *
    make_forward_remote_port(struct io_backend *backend,
    			 struct address_info *remote,
    			 struct address_info *target)
    {
      CAST_SUBTYPE(command, res,
    	       forward_remote_port(make_connect_port(backend, target), remote));
    
      debug("tcpforward_commands.c: forward_remote_port\n");
      
      return res;
    }
    
    /* Takes a callback function and returns a channel_open
     * handler. */
    DEFINE_COMMAND(make_direct_tcpip_handler)
         (struct command *s UNUSED,
          struct lsh_object *x,
          struct command_continuation *c,
          struct exception_handler *e UNUSED)
    {
      CAST_SUBTYPE(command, callback,  x);
    
      trace("tcpforward_commands.c: do_make_open_tcp_handler\n");
      
      COMMAND_RETURN(c,
    		 &make_channel_open_direct_tcpip(callback)->super);
    }
    
    /* Takes a callback function and returns a global_request handler. */
    DEFINE_COMMAND(make_tcpip_forward_handler)
         (struct command *s UNUSED,
          struct lsh_object *x,
          struct command_continuation *c,
          struct exception_handler *e UNUSED)
    {
      CAST_SUBTYPE(command, callback,  x);
    
      debug("tcpforward_commands.c: make_tcpip_forward_handler\n");
      
      COMMAND_RETURN(c,
    		 &make_tcpip_forward_request(callback)->super);
    }
    
    
    /* Commands to install handlers */
    struct install_info install_direct_tcpip_handler =
    STATIC_INSTALL_OPEN_HANDLER(ATOM_DIRECT_TCPIP);
    
    struct install_info install_forwarded_tcpip_handler =
    STATIC_INSTALL_OPEN_HANDLER(ATOM_FORWARDED_TCPIP);
    
    
    /* Server side callbacks */
    
    /* Make this non-static? */
    /* GABA:
       (expr
         (name direct_tcpip_hook)
         (params
           (connect object command))
         (expr
           (lambda (connection)
             (install_direct_tcpip connection
    	   (direct_tcpip_handler (lambda (port)
    	     (tcpip_connect_io (connect connection port))))))))
    */
    
    struct command *
    make_direct_tcpip_hook(struct io_backend *backend)
    {
      CAST_SUBTYPE(command, res,
    	       direct_tcpip_hook(make_connect_connection(backend)));
    
      debug("tcpforward_commands.c: make_direct_tcpip_hook\n");
    
      return res;
    }
    
    struct install_info install_tcpip_forward_handler =
    STATIC_INSTALL_GLOBAL_HANDLER(ATOM_TCPIP_FORWARD);
    
    
    /* GABA:
       (expr
         (name tcpip_forward_hook)
         ; FIXME: Don't use globals.
         (globals
           (install "&install_tcpip_forward_handler.super.super.super")
           (handler "&make_tcpip_forward_handler.super"))
         (params
           (backend object io_backend))
         (expr
           (lambda (connection)
             ;; Called when the ssh-connection is established
             (install connection
    	   (handler (lambda (port)
    	     ;; Called when the client requests remote forwarding.
    	     ;; It should return the fd associated with the port.
    	     ;; NOTE: The caller, do_tcpip_forward_request, is responsible
    	     ;; for handling I/O exceptions, and for remembering the port.
    	     (listen_callback (lambda (peer)
      		  		;; Called when someone connects to the
    		  		;; forwarded port.
    				;; Remembering is done by open_direct_tcpip
    				;; and new_tcpip_channel.
    				(tcpip_start_io
    		  		  (catch_channel_open 
    		  		    (open_forwarded_tcpip port peer) connection)))
    		  	      backend port))))))))
    */
    
    struct command *
    make_tcpip_forward_hook(struct io_backend *backend)
    {
      CAST_SUBTYPE(command, res, tcpip_forward_hook(backend));
    
      debug("tcpforward_commands.c: tcpip_forward_hook\n");
      
      return res;
    }