channel_forward.c 6.08 KB
Newer Older
1
2
3
4
/* channel_forward.h
 *
 * General channel type for forwarding data to an fd
 *
5
 */
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 1998, 2001 Balzs Scheidler, 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
 */

26
27
28
29
30
31
32
33
#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <assert.h>
#include <errno.h>
#include <string.h>

34
35
36
#include "channel_forward.h"

#include "io.h"
Niels Möller's avatar
Niels Möller committed
37
#include "lsh_string.h"
38
39
40
41
42
43
44
45
#include "ssh.h"
#include "werror.h"
#include "xalloc.h"

#define GABA_DEFINE
#include "channel_forward.h.x"
#undef GABA_DEFINE

Niels Möller's avatar
Niels Möller committed
46
47
48
49
/* We don't use channel_read_state_close and channel_write_state_close. */
static void
do_kill_channel_forward(struct resource *s)
{  
50
  CAST_SUBTYPE(channel_forward, self, s);
Niels Möller's avatar
Niels Möller committed
51
52
53
54
55
56
57
58
59
  if (self->super.super.alive)
    {
      trace("do_kill_channel_forward\n");
      
      self->super.super.alive = 0;
      io_close_fd(self->read.fd);
    }
}

60
void
Niels Möller's avatar
Niels Möller committed
61
channel_forward_shutdown(struct channel_forward *self)
62
{
Niels Möller's avatar
Niels Möller committed
63
64
65
66
67
68
69
70
71
72
73
74
  if (shutdown (self->write.fd, SHUT_WR) < 0)
    werror("close_fd_write, shutdown failed, %e\n", errno);

  assert(self->super.sinks);
  self->super.sinks--;
  channel_maybe_close(&self->super);  
}

static void *
oop_write_socket(oop_source *source UNUSED,
		 int fd, oop_event event, void *state)
{
75
  CAST_SUBTYPE(channel_forward, self, (struct lsh_object *) state);
76
  
Niels Möller's avatar
Niels Möller committed
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
  assert(event == OOP_WRITE);
  assert(fd == self->write.fd);

  if (channel_io_flush(&self->super, &self->write) == CHANNEL_IO_EOF)
    channel_forward_shutdown(self);

  return OOP_CONTINUE;
}

static void
do_channel_forward_receive(struct ssh_channel *s, int type,
			   uint32_t length, const uint8_t *data)
{
  CAST_SUBTYPE(channel_forward, self, s);

  if (type != CHANNEL_DATA)
    werror("Ignoring unexpected extended data on forwarded channel.\n");
  else
95
    {
Niels Möller's avatar
Niels Möller committed
96
97
98
      if (channel_io_write(&self->super, &self->write, oop_write_socket,
			   length, data) == CHANNEL_IO_EOF)
	channel_forward_shutdown(self);
99
100
101
    }
}

Niels Möller's avatar
Niels Möller committed
102
103
104
105
static void *
oop_read_socket(oop_source *source UNUSED,
		int fd, oop_event event, void *state)
{
106
  CAST_SUBTYPE(channel_forward, self, (struct lsh_object *) state);
Niels Möller's avatar
Niels Möller committed
107
108
109
110
111
112
113
114
115
116
117
118
119
120
  uint32_t done;
  
  assert(fd == self->read.fd);
  assert(event == OOP_READ);

  if (channel_io_read(&self->super, &self->read, &done) == CHANNEL_IO_OK
      && done > 0)
    channel_transmit_data(&self->super,
			  done, lsh_string_data(self->read.buffer));

  return OOP_CONTINUE;
}

/* We may send more data */
121
122
static void
do_channel_forward_send_adjust(struct ssh_channel *s,
Niels Möller's avatar
Niels Möller committed
123
			       uint32_t i UNUSED)
124
{
125
  CAST_SUBTYPE(channel_forward, self, s);
Niels Möller's avatar
Niels Möller committed
126
127

  channel_io_start_read(&self->super, &self->read, oop_read_socket);
128
129
}

130
131
132
133
134
135
136
void
channel_forward_start_read(struct channel_forward *self)
{
  if (self->super.send_window_size)
    channel_io_start_read(&self->super, &self->read, oop_read_socket);
}

137
138
139
140
141
142
/* NOTE: Because this function is called by
 * do_open_forwarded_tcpip_continuation, the same restrictions apply.
 * I.e we can not assume that the channel is completely initialized
 * (channel_open_continuation has not yet done its work), and we can't
 * send any packets. */
void
Niels Möller's avatar
Niels Möller committed
143
channel_forward_start_io(struct channel_forward *self)
144
{
Niels Möller's avatar
Niels Möller committed
145
146
147
148
149
  self->super.receive = do_channel_forward_receive;
  self->super.send_adjust = do_channel_forward_send_adjust;

  self->super.sources++;
  self->super.sinks ++;
150
151

  channel_forward_start_read(self);
152
153
}

154
155
156
157
158
159
160
161
162
163
static void
do_channel_forward_event(struct ssh_channel *s, enum channel_event event)
{
  CAST_SUBTYPE(channel_forward, self, s);

  switch(event)
    {
    case CHANNEL_EVENT_CONFIRM:
      channel_forward_start_io(self);
      break;
164
165
166
167
    case CHANNEL_EVENT_DENY:
    case CHANNEL_EVENT_CLOSE:
      /* Do nothing */
      break;      
168
169
170
171
172
173
174
175
    case CHANNEL_EVENT_EOF:
      if (!self->write.state->length)
	channel_forward_shutdown(self);
      break;
    case CHANNEL_EVENT_STOP:
      channel_io_stop_read(&self->read);
      break;
    case CHANNEL_EVENT_START:
176
      channel_forward_start_read(self);
177
178
179
180
181
182
      break;
    }
}

#define FORWARD_READ_BUFFER_SIZE 0x4000

183
/* NOTE: It's the caller's responsibility to call io_register_fd. */
184
185
void
init_channel_forward(struct channel_forward *self,
186
187
		     int socket, uint32_t initial_window,
		     void (*event)(struct ssh_channel *, enum channel_event))
188
189
{
  init_channel(&self->super,
190
	       do_kill_channel_forward, event);
191
192
193
194
195
196
197
198
199
200
201
202
203

  /* The rest of the callbacks are not set up until
   * channel_forward_start_io. */

  self->super.rec_window_size = initial_window;

  /* FIXME: Make maximum packet size configurable. */
  self->super.rec_max_packet = SSH_MAX_PACKET;

  init_channel_read_state(&self->read, socket, FORWARD_READ_BUFFER_SIZE);
  init_channel_write_state(&self->write, socket, initial_window);
}

204
/* NOTE: It's the caller's responsibility to call io_register_fd. */
205
206
207
208
struct channel_forward *
make_channel_forward(int socket, uint32_t initial_window)
{
  NEW(channel_forward, self);
209
210
  init_channel_forward(self, socket, initial_window,
		       do_channel_forward_event);
211
212
213
214
  
  return self;
}

215
216
217
218
219
/* 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. */

Niels Möller's avatar
Niels Möller committed
220
DEFINE_COMMAND(forward_start_io_command)
221
222
223
224
225
226
227
228
229
230
231
232
233
     (struct command *s UNUSED,
      struct lsh_object *x,
      struct command_continuation *c,
      struct exception_handler *e UNUSED)
{
  CAST_SUBTYPE(channel_forward, channel, x);

  assert(channel);
  
  channel_forward_start_io(channel);

  COMMAND_RETURN(c, channel);  
}