Skip to content
Snippets Groups Projects
Select Git revision
  • f44a94847480df131a1dfc83ed2d2fc9063a4145
  • master default protected
  • hpke
  • ppc-chacha-4core
  • delete-internal-name-mangling
  • master-updates
  • ppc-gcm
  • ppc-chacha-2core
  • refactor-ecc-mod
  • ppc-chacha-core
  • use-mpn_cnd-functions
  • optimize-ecc-invert
  • default-m4-quote-char
  • power-asm-wip
  • test-fat
  • chacha-3core-neon
  • x86_64-salsa20-2core
  • salsa20-2core-neon
  • bcrypt
  • arm-salsa20-chacha-vsra
  • test-shlib-dir
  • 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
  • nettle_3.5rc1
  • nettle_3.4.1_release_20181204
  • nettle_3.4.1rc1
  • nettle_3.4_release_20171119
  • nettle_3.4rc2
  • nettle_3.4rc1
  • nettle_3.3_release_20161001
  • nettle_3.2_release_20160128
  • nettle_3.1.1_release_20150424
  • nettle_3.1_release_20150407
  • nettle_3.1rc3
  • nettle_3.1rc2
  • nettle_3.1rc1
  • nettle_3.0_release_20140607
41 results

desTest.c

Blame
  • Forked from Nettle / nettle
    Source project has a limited visibility.
    client.c 13.19 KiB
    /* client.c
     *
     * $Id$ */
    
    /* lsh, an implementation of the ssh protocol
     *
     * Copyright (C) 1998 Niels Mller
     *
     * 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 "client.h"
    
    #include "abstract_io.h"
    #include "channel.h"
    #include "channel_commands.h"
    #include "connection.h"
    #include "crypto.h"
    #include "debug.h"
    #include "encrypt.h"
    #include "format.h"
    #include "pad.h"
    #include "parse.h"
    #include "service.h"
    #include "ssh.h"
    #include "translate_signal.h"
    #include "tty.h"
    #include "unpad.h"
    #include "werror.h"
    #include "xalloc.h"
    #include "compress.h"
    
    #include <signal.h>
    
    #include <string.h>
    #include <assert.h>
    
    #include "client.c.x"
    
    /* Start a service that the server has accepted (for instance
     * ssh-userauth). */
    /* GABA:
       (class
         (name accept_service_handler)
         (super packet_handler)
         (vars
           (service simple UINT32)
           (c object command_continuation)
           ;; Do we really need the exception handler here?
           (e object exception_handler)))
    */
    
    static void
    do_accept_service(struct packet_handler *c,
    		  struct ssh_connection *connection,
    		  struct lsh_string *packet)
    {
      CAST(accept_service_handler, closure, c);
    
      struct simple_buffer buffer;
      unsigned msg_number;
      UINT32 name;
    
      simple_buffer_init(&buffer, packet->length, packet->data);
      
      if (parse_uint8(&buffer, &msg_number)
          && (msg_number == SSH_MSG_SERVICE_ACCEPT)
          && (
    #if DATAFELLOWS_WORKAROUNDS
    	  (connection->peer_flags & PEER_SERVICE_ACCEPT_KLUDGE)
    #else
    	  0
    #endif
    	  || (parse_atom(&buffer, &name)
    	      && (name == closure->service)))
          && parse_eod(&buffer))
        {
          lsh_string_free(packet);
          connection->dispatch[SSH_MSG_SERVICE_ACCEPT] = connection->fail;
          
          COMMAND_RETURN(closure->c, connection);
        }
      else
        {
          lsh_string_free(packet);
          PROTOCOL_ERROR(closure->e, "Invalid SSH_MSG_SERVICE_ACCEPT message");
        }
    }
    
    struct packet_handler *
    make_accept_service_handler(UINT32 service,
    			    struct command_continuation *c,
    			    struct exception_handler *e)
    {
      NEW(accept_service_handler, closure);
    
      closure->super.handler = do_accept_service;
      closure->service = service;
      closure->c = c;
      closure->e = e;
      
      return &closure->super;
    }
    
    /* GABA:
       (class
         (name request_service)
         (super command)
         (vars
           (service simple int)))
           ;; (service object ssh_service)))
    */
    
    static void
    do_request_service(struct command *s,
    		   struct lsh_object *x,
    		   struct command_continuation *c,
    		   struct exception_handler *e)
    {
      CAST(request_service, self, s);
      CAST(ssh_connection, connection, x);
      
      connection->dispatch[SSH_MSG_SERVICE_ACCEPT]
        = make_accept_service_handler(self->service, c, e);
      
      C_WRITE(connection,
    	  format_service_request(self->service));
    }
    
    struct command *make_request_service(int service)
    {
      NEW(request_service, closure);
    
      closure->super.call = do_request_service;
      closure->service = service;
    
      return &closure->super;
    }
    
    /* ;; GABA:
       (class
         (name request_info)
         (vars
           ; Next request
           (next object request_info)
           (want_reply . int)
           ; If true, close the channel if the request fails
           (essential . int)
    
           (format method "struct lsh_string *" "struct ssh_channel *c")
           ; Called with a success/fail indication
           (result method int "struct ssh_channel *c" int)))
    */
    
    #define REQUEST_FORMAT(r, c) ((r)->format((r), (c)))
    #define REQUEST_RESULT(r, c, i) ((r)->result((r), (c), (i)))
    
    /* Initiate and manage a session */
    /* GABA:
       (class
         (name client_session)
         (super ssh_channel)
         (vars
           ; Exec or shell request. 
           ;(final_request simple int)
           ;(args string)
    
           ; List of requests
           (requests object request_info)
      
           ; To access stdio
           (in object lsh_fd)
           (out object lsh_fd)
           (err object lsh_fd)
    
           ; Where to save the exit code.
           (exit_status simple "int *")))
    */
    
    /* Callback used when the server sends us eof */
    static void
    do_client_session_eof(struct ssh_channel *c)
    {
      CAST(client_session, session, c);
      
      close_fd(session->in, 0);
    }  
    
    static void
    do_client_session_close(struct ssh_channel *c)
    {
      static const struct exception finish_exception
        = STATIC_EXCEPTION(EXC_FINISH_PENDING, "Session closed.");
    
      EXCEPTION_RAISE(c->e, &finish_exception);
    }
    
    
    /* GABA:
       (class
         (name exit_handler)
         (super channel_request)
         (vars
           (exit_status simple "int *")))
    */
    
    static void
    do_exit_status(struct channel_request *c,
    	       struct ssh_channel *channel,
    	       struct ssh_connection *connection UNUSED,
    	       UINT32 type UNUSED,
    	       int want_reply,
    	       struct simple_buffer *args,
    	       struct command_continuation *s,
    	       struct exception_handler *e)
    {
      CAST(exit_handler, closure, c);
      UINT32 status;
    
      if (!want_reply
          && parse_uint32(args, &status)
          && parse_eod(args))
        {
          *closure->exit_status = status;
    
          ALIST_SET(channel->request_types, ATOM_EXIT_STATUS, NULL);
          ALIST_SET(channel->request_types, ATOM_EXIT_SIGNAL, NULL);
    
          /* Send EOF, if we haven't done that already. */
          /* FIXME: Make this behaviour configurable, there may be some
           * child process alive that we could talk to. */
    
          channel_eof(channel);
          COMMAND_RETURN(s, NULL);
        }
      else
        /* Invalid request */
        PROTOCOL_ERROR(e, "Invalid exit-status message");
    }
    
    static void
    do_exit_signal(struct channel_request *c,
    	       struct ssh_channel *channel,
    	       struct ssh_connection *connection UNUSED,
    	       UINT32 type UNUSED,
     	       int want_reply,
    	       struct simple_buffer *args,
    	       struct command_continuation *s,
    	       struct exception_handler *e)
    {
      CAST(exit_handler, closure, c);
    
      UINT32 signal;
      int core;
    
      UINT8 *msg;
      UINT32 length;
    
      UINT8 *language;
      UINT32 language_length;
      
      if (!want_reply
          && parse_uint32(args, &signal)
          && parse_boolean(args, &core)
          && parse_string(args, &length, &msg)
          && parse_string(args, &language_length, &language)
          && parse_eod(args))
        {
          /* FIXME: What exit status should be returned when the remote
           * process dies violently? */
    
          *closure->exit_status = 7;
    
          signal = signal_network_to_local(signal);
    
          werror("%us", length, msg);
          werror("Remote process was killed by %z.%z\n",
    	     signal ? STRSIGNAL(signal) : "an unknown signal",
    	     core ? "(core dumped remotely)\n": "");
    
          ALIST_SET(channel->request_types, ATOM_EXIT_STATUS, NULL);
          ALIST_SET(channel->request_types, ATOM_EXIT_SIGNAL, NULL);
    
          /* Sent EOF, if we haven't done that already. */
          /* FIXME: Make this behaviour configurable, there may be some
           * child process alive that we could talk to. */
    
          channel_eof(channel);
          COMMAND_RETURN(s, NULL);
        }
      else
        /* Invalid request */
        PROTOCOL_ERROR(e, "Invalid exit-signal message");
    }
    
    struct channel_request *make_handle_exit_status(int *exit_status)
    {
      NEW(exit_handler, self);
    
      self->super.handler = do_exit_status;
    
      self->exit_status = exit_status;
    
      return &self->super;
    }
    
    struct channel_request *make_handle_exit_signal(int *exit_status)
    {
      NEW(exit_handler, self);
    
      self->super.handler = do_exit_signal;
    
      self->exit_status = exit_status;
    
      return &self->super;
    }
    
    /* Receive channel data */
    static void
    do_receive(struct ssh_channel *c,
    	   int type, struct lsh_string *data)
    {
      CAST(client_session, closure, c);
      
      switch(type)
        {
        case CHANNEL_DATA:
          A_WRITE(&closure->out->write_buffer->super, data);
          break;
        case CHANNEL_STDERR_DATA:
          A_WRITE(&closure->err->write_buffer->super, data);
          break;
        default:
          fatal("Internal error!\n");
        }
    }
    
    /* We may send more data */
    static void
    do_send_adjust(struct ssh_channel *s,
    	       UINT32 i UNUSED)
    {
      CAST(client_session, self, s);
    
      assert(self->in->read);
    
      self->in->want_read = 1;
    }
    
    /* We have a remote shell */
    static void
    do_client_io(struct command *s UNUSED,
    	     struct lsh_object *x,
    	     struct command_continuation *c,
    	     struct exception_handler *e UNUSED)
    
    {
      CAST(client_session, session, x);
      struct ssh_channel *channel = &session->super;
      assert(x);
    
      /* Set up write fd:s. */
      
      channel->receive = do_receive;
    
      /* FIXME: It seems a little kludgy to modify
       * exception handlers here; it would be better to create the
       * fd-objects at a point where the right exception handlers can be
       * installed from the start. */
      session->out->e
        = make_channel_io_exception_handler(channel,
    					"lsh: I/O error on stdout",
    					session->out->e,
    					HANDLER_CONTEXT);
    
      session->err->e
        = make_channel_io_exception_handler(channel,
    					"lsh: I/O error on stderr",
    					session->err->e,
    					HANDLER_CONTEXT);
    
      /* Set up the fd we read from. */
      channel->send_adjust = do_send_adjust;
    
      session->in->read = make_channel_read_data(channel);
    
      /* FIXME: Perhaps there is some way to arrange that channel.c calls
       * the CHANNEL_SEND_ADJUST method instead? */
      if (session->super.send_window_size)
        session->in->want_read = 1;
      
      session->in->close_callback
        = make_channel_read_close_callback(channel);
    
      /* Make sure stdio is closed properly if the channel or connection dies */
      REMEMBER_RESOURCE(channel->resources, &session->in->super);
      REMEMBER_RESOURCE(channel->resources, &session->out->super);
      REMEMBER_RESOURCE(channel->resources, &session->err->super);
      
      ALIST_SET(channel->request_types, ATOM_EXIT_STATUS,
    	    make_handle_exit_status(session->exit_status));
      ALIST_SET(channel->request_types, ATOM_EXIT_SIGNAL,
    	    make_handle_exit_signal(session->exit_status));
    
      channel->eof = do_client_session_eof;
          
      COMMAND_RETURN(c, channel);
    }
    
    struct command client_io =
    { STATIC_HEADER, do_client_io };
    
    
    struct ssh_channel *
    make_client_session(struct lsh_fd *in,
    		    struct lsh_fd *out,
    		    struct lsh_fd *err,
    		    UINT32 initial_window,
    		    int *exit_status)
    {
      NEW(client_session, self);
    
      init_channel(&self->super);
    
      /* Makes sure the pending_close bit is set whenever this session
       * dies, no matter when or how. */
      self->super.close = do_client_session_close;
      
      self->super.rec_window_size = initial_window;
    
      /* FIXME: Make maximum packet size configurable */
      self->super.rec_max_packet = SSH_MAX_PACKET - SSH_CHANNEL_MAX_PACKET_FUZZ;
    
      self->super.request_types = make_alist(0, -1);
    
      /* self->expect_close = 0; */
      self->in = in;
      self->out = out;
      self->err = err;
    
      /* Flow control */
      out->write_buffer->report = &self->super.super;
      err->write_buffer->report = &self->super.super;
      
      self->exit_status = exit_status;
      
      return &self->super;
    }
    
    /* GABA:
       (class
         (name session_open_command)
         (super channel_open_command)
         (vars
           ; This command can only be executed once,
           ; so we can allocate the session object in advance.
           (session object ssh_channel)))
    */
    
    static struct ssh_channel *
    new_session(struct channel_open_command *s,
    	    struct ssh_connection *connection,
    	    UINT32 local_channel_number,
    	    struct lsh_string **request)
    {
      CAST(session_open_command, self, s);
      struct ssh_channel *res;
    
      self->session->write = connection->write;
      
      *request = format_channel_open(ATOM_SESSION,
    				 local_channel_number,
    				 self->session, "");
      
      res = self->session;
    
      /* Make sure this command can not be invoked again */
      self->session = NULL;
    
      return res;
    }
    
    struct command *make_open_session_command(struct ssh_channel *session)
    {
      NEW(session_open_command, self);
      self->super.super.call = do_channel_open_command;
      self->super.new_channel = new_session;
      self->session = session;
    
      return &self->super.super;
    }
    
    
    static struct lsh_string *
    do_format_shell_request(struct channel_request_command *s UNUSED,
    			struct ssh_channel *channel,
    			struct command_continuation **c)
    {
      return format_channel_request(ATOM_SHELL, channel, !!*c, "");
    }
    
    struct channel_request_command request_shell =
    { { STATIC_HEADER, do_channel_request_command }, do_format_shell_request };
    
    
    /* GABA:
       (class
         (name exec_request)
         (super channel_request_command)
         (vars
           (command string)))
    */
    
    static struct lsh_string *
    do_format_exec_request(struct channel_request_command *s,
    		       struct ssh_channel *channel,
    		       struct command_continuation **c)
    {
      CAST(exec_request, self, s);
    
      verbose("lsh: Requesting remote exec.\n");
    
      return format_channel_request(ATOM_EXEC, channel,
    				!!*c, "%S", self->command);
    }
    
    struct command *
    make_exec_request(struct lsh_string *command)
    {
      NEW(exec_request, req);
    
      req->super.format_request = do_format_exec_request;
      req->super.super.call = do_channel_request_command;
      req->command = command;
    
      return &req->super.super;
    }