Exemplo n.º 1
0
static void
do_service_request(struct packet_handler *c,
		   struct ssh_connection *connection,
		   struct lsh_string *packet)
{
  CAST(service_handler, closure, c);

  struct simple_buffer buffer;
  unsigned msg_number;
  int name;
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_SERVICE_REQUEST)
      && parse_atom(&buffer, &name)
      && parse_eod(&buffer))
    {
      if (name)
	{
	  CAST_SUBTYPE(command, service, ALIST_GET(closure->services, name));
	  if (service)
	    {
	      /* Don't accept any further service requests */
	      connection->dispatch[SSH_MSG_SERVICE_REQUEST]
		= &connection_fail_handler;

	      /* Start service */
#if DATAFELLOWS_WORKAROUNDS
	      if (connection->peer_flags & PEER_SERVICE_ACCEPT_KLUDGE)
		C_WRITE(connection, format_service_accept_kludge());
	      else
#endif /* DATAFELLOWS_WORKAROUNDS */
		C_WRITE(connection, format_service_accept(name));
	      
	      COMMAND_CALL(service, connection,
			   closure->c, closure->e);
	      return;
	    }
	}
      EXCEPTION_RAISE(connection->e,
		      make_protocol_exception(SSH_DISCONNECT_SERVICE_NOT_AVAILABLE, NULL));
      
    }
  else
      PROTOCOL_ERROR(connection->e, "Invalid SERVICE_REQUEST message");
}
Exemplo n.º 2
0
static void
lshd_service_request_handler(struct transport_forward *self,
			     uint32_t length, const uint8_t *packet)
{
  struct simple_buffer buffer;
  unsigned msg_number;

  const uint8_t *name;
  uint32_t name_length;

  simple_buffer_init(&buffer, length, packet);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_SERVICE_REQUEST)
      && parse_string(&buffer, &name_length, &name)
      && parse_eod(&buffer))
    {
      CAST(lshd_context, ctx, self->super.ctx);
      const struct service_entry *service
	= service_config_lookup(ctx->service_config,
				name_length, name);
      
      if (service)
	{
	  int pipe[2];
	  pid_t child;

	  if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe) < 0)
	    {
	      werror("lshd_service_request_handler: socketpair failed: %e.\n",
		     errno);
	      transport_disconnect(&self->super,
				   SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
				   "Service could not be started");
	      return;
	    }

	  child = fork();
	  if (child < 0)
	    {
	      werror("lshd_service_request_handler: fork failed: %e.\n",
		     errno);
	      close(pipe[0]);
	      close(pipe[1]);
	      transport_disconnect(&self->super,
				   SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
				   "Service could not be started");
	      return;
	    }
	  if (child)
	    {
	      /* Parent process */
	      close(pipe[1]);

	      transport_send_packet(&self->super, TRANSPORT_WRITE_FLAG_PUSH,
				    format_service_accept(name_length, name));

	      /* Setup forwarding. Replaces event_handler and packet_handler. */
	      transport_forward_setup(self, pipe[0], pipe[0]);
	    }
	  else
	    {
	      /* Child process */
	      struct arglist args;
	      const char *program;
	      unsigned i;

	      close(pipe[0]);
	      dup2(pipe[1], STDIN_FILENO);
	      dup2(pipe[1], STDOUT_FILENO);
	      close(pipe[1]);

	      /* FIXME: Pass sufficient information so that
		 $SSH_CLIENT can be set properly. */
	      arglist_init (&args);

	      program = service->args.argv[0];
	      arglist_push (&args, program);

	      /* If not absolute, interpret it relative to
		 libexecdir. */
	      if (program[0] != '/')
		program = lsh_get_cstring(ssh_format("%lz/%lz",
						     ctx->service_config->libexec_dir,
						     program));
	      
	      for (i = 1; i < service->args.argc; i++)
		{
		  const char *arg = service->args.argv[i];
		  if (arg[0] == '$')
		    {
		      if (!strcmp(arg+1, "(session_id)"))
			arg = lsh_get_cstring(ssh_format("%lxS",
							 self->super.session_id));
		    }
		  arglist_push (&args, arg);
		}
	      debug("exec of service %s, program %z. Argument list:\n",
		    name_length, name, program);
	      for (i = 0; i < args.argc; i++)
		debug("  %z\n", args.argv[i]);

	      execv(program, (char **) args.argv);

	      werror("lshd_service_request_handler: exec of %z failed: %e.\n",
		     args.argv[0], errno);
	      _exit(EXIT_FAILURE);
	    }
	}
      else
	transport_disconnect(&self->super,
			     SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
			      "Service not available");
    }
  else
    transport_protocol_error(&self->super, "Invalid SERVICE_REQUEST");
}