server_x11.c 5.84 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/* server_x11.c
 *
 * $id:$
 *
 */

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 2002 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "server_x11.h"

28
#include "format.h"
29
#include "reaper.h"
30
#include "resource.h"
31
#include "userauth.h"
Niels Möller's avatar
Niels Möller committed
32
#include "werror.h"
33 34
#include "xalloc.h"

35 36 37 38 39
#include <string.h>

#include <unistd.h>
#include <fcntl.h>

40 41 42 43 44
#define GABA_DEFINE
#include "server_x11.h.x"
#undef GABA_DEFINE

#include "server_x11.c.x"
Niels Möller's avatar
Niels Möller committed
45

46 47 48 49
/* Disabled in the 1.4 series. */
#undef WITH_X11_FORWARD
#define WITH_X11_FORWARD 0

Niels Möller's avatar
Niels Möller committed
50
#if WITH_X11_FORWARD
51

52 53
#define XAUTH_DEBUG_TO_STDERR 0

54 55 56 57 58 59 60 61 62 63 64 65
#define X11_MIN_COOKIE_LENGTH 10

/* GABA:
   (class
     (name xauth_exit_callback)
     (super exit_callback)
     (vars
       (c object command_continuation)
       (e object exception_handler)))
*/

static void
66 67
do_xauth_exit(struct exit_callback *s, int signaled,
	      int core UNUSED, int value)
Niels Möller's avatar
Niels Möller committed
68
{
69 70 71 72 73 74 75 76
  CAST(xauth_exit_callback, self, s);
  
  if (signaled || value)
    {
      /* xauth failed */
      const struct exception xauth_failed
	= STATIC_EXCEPTION(EXC_CHANNEL_REQUEST, "xauth failed");
      EXCEPTION_RAISE(self->e, &xauth_failed);
77 78 79 80
      if (signaled)
	werror("xauth invocation failed: Signal %d\n", value);
      else
	werror("xauth invocation failed: exit code: %d\n", value);
81 82 83
    }
  else
    /* NOTE: Return value is ignored. */
84
    COMMAND_RETURN(self->c, NULL);
Niels Möller's avatar
Niels Möller committed
85 86
}

87 88 89
static struct exit_callback *
make_xauth_exit_callback(struct command_continuation *c,
			 struct exception_handler *e)
Niels Möller's avatar
Niels Möller committed
90
{
91 92 93 94
  NEW(xauth_exit_callback, self);
  self->super.exit = do_xauth_exit;
  self->c = c;
  self->e = e;
95 96 97 98 99 100 101 102 103 104 105 106

  return &self->super;
}

/* NOTE: We don't check the arguments for spaces or other magic
 * characters. The xauth process in unprivileged, and the user is
 * properly authenticated to call it with arbitrary commands. We still
 * check for NUL characters, though. */
static int
bad_string(UINT32 length, const UINT8 *data)
{
  return !!memchr(data, '\0', length);
Niels Möller's avatar
Niels Möller committed
107
}
108

109 110 111
/* FIXME: Use autoconf */
#define XAUTH_PROGRAM "/usr/X11R6/bin/xauth"

112 113 114
/* On success, returns 1 and sets *DISPLAY and *XAUTHORITY */
struct server_x11_info *
server_x11_setup(struct ssh_channel *channel, struct lsh_user *user,
115 116 117 118 119
		 UINT32 protocol_length, const UINT8 *protocol,
		 UINT32 cookie_length, const UINT8 *cookie,
		 UINT32 screen,
		 struct command_continuation *c,
		 struct exception_handler *e)
120 121 122 123 124 125 126 127 128 129 130 131
{
  /* Get a free socket under /tmp/.X11-unix/ */
  UINT32 display_number = 17;

  struct lsh_string *display;
  struct lsh_string *xauthority;
  
  const char *tmp;

  /* FIXME: Bind socket, set up forwarding */
  struct lsh_fd *socket = NULL;

132
  if (bad_string(protocol_length, protocol))
133 134 135 136 137
    {
      werror("server_x11_setup: Bogus protocol name.\n");
      return NULL;
    }
  
138
  if (bad_string(cookie_length, cookie))
139 140 141 142 143
    {
      werror("server_x11_setup: Bogus cookie.\n");
      return NULL;
    }
  
144
  if (cookie_length < X11_MIN_COOKIE_LENGTH)
145 146 147 148 149
    {
      werror("server_x11_setup: Cookie too small.\n");
      return NULL;
    }

150
  tmp = getenv("TMPDIR");
151 152 153
  if (!tmp)
    tmp = "tmp";
  
154
  display = ssh_format(":%di.%di", display_number, screen);
155 156 157 158
  xauthority = ssh_format("/%lz/.lshd.%lS.Xauthority", tmp, user->name);

  {
    struct spawn_info spawn;
159
    const char *args[2] = { "-c", XAUTH_PROGRAM };
160
    const struct env_value env[1] =
161
      { {"XAUTHORITY", xauthority } };
162 163

    struct lsh_process *process;
164 165 166

    int null;

167
    memset(&spawn, 0, sizeof(spawn));
168 169 170 171 172 173 174
    /* FIXME: Arrange that stderr data (and perhaps stdout data as
     * well) is sent as extrended data on the channel. To do that, we
     * need another channel flag to determine whether or not EOF
     * should be sent when the number of sources gets down to 0. */
#if XAUTH_DEBUG_TO_STDERR
    null = dup(STDERR_FILENO);
#else
175
    null = open("/dev/null", O_WRONLY);
176
#endif
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
    if (null < 0)
      goto fail;

    /* [0] for reading, [1] for writing */
    if (!lsh_make_pipe(spawn.in))
      {
	close(null);
	goto fail;
      }
    spawn.out[0] = -1; spawn.out[1] = null;
    spawn.err[0] = -1; spawn.err[1] = null;
    
    spawn.peer = NULL;
    spawn.pty = NULL;
    spawn.login = 0;
    spawn.argc = 2;
    spawn.argv = args;
    spawn.env_length = 1;
    spawn.env = env;
196 197 198 199 200

    process = USER_SPAWN(user, &spawn, make_xauth_exit_callback(c, e));
    if (process)
      {
	NEW(server_x11_info, info);
201 202 203 204 205 206 207 208 209 210 211 212 213
	static const struct report_exception_info report =
	  STATIC_REPORT_EXCEPTION_INFO(EXC_IO, EXC_IO, "writing xauth stdin");

	struct lsh_fd *in
	  = io_write(make_lsh_fd(spawn.in[1],
				 "xauth stdin",
				 make_report_exception_handler
				 (&report, e, HANDLER_CONTEXT)),
		     1024, NULL);

	A_WRITE(&in->write_buffer->super,
		/* NOTE: We pass arbitrary data to the xauth process,
		 * if the user so wish. */
214
		 ssh_format("add %lS %ls %ls\n",
215 216 217 218 219 220 221 222
			   display,
			   protocol_length, protocol,
			   cookie_length, cookie));
	close_fd_write(in);

	remember_resource(channel->resources, &process->super);
	remember_resource(channel->resources, &in->super);	
	
223 224
	info->display = display;
	info->xauthority = xauthority;
225
	
226 227 228 229
	return info;
      }
    else
      {
230 231 232
	close(spawn.in[0]);
	close(spawn.in[1]);
      fail:
233 234 235 236 237 238 239
	lsh_string_free(display);
	lsh_string_free(xauthority);
	return NULL;
      }
  }
}

Niels Möller's avatar
Niels Möller committed
240
#endif /* WITH_X11_FORWARD */