connection.c 7.38 KB
Newer Older
1
2
3
4
/* connection.c
 *
 */

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 1998 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

24
#include "connection.h"
25

26
#include "debug.h"
27
#include "encrypt.h"
28
#include "format.h"
29
#include "disconnect.h"
30
#include "keyexchange.h"
31
#include "compress.h"
32
#include "packet_ignore.h"
33
#include "pad.h"
34
35
36
#include "ssh.h"
#include "werror.h"
#include "xalloc.h"
37

38
39
40
41
#define CLASS_DEFINE
#include "connection.h.x"
#undef CLASS_DEFINE

42
static int handle_connection(struct abstract_write *w,
43
			     struct lsh_string *packet)
44
{
45
  CAST(ssh_connection, closure, w);
46
  UINT8 msg;
Niels Möller's avatar
Niels Möller committed
47

48
49
  if (!packet->length)
    {
50
      wwrite("connection.c: Received empty packet!\n");
Niels Möller's avatar
Niels Möller committed
51
      return LSH_FAIL | LSH_DIE;
52
    }
53

54
  msg = packet->data[0];
55

56
  debug("handle_connection: Received packet of type %d\n", msg);
57
58

  switch(closure->kex_state)
59
    {
60
61
62
    case KEX_STATE_INIT:
      if (msg == SSH_MSG_NEWKEYS)
	{
63
	  wwrite("Unexpected NEWKEYS message!\n");
64
	  lsh_string_free(packet);
Niels Möller's avatar
Niels Möller committed
65
	  return LSH_FAIL | LSH_DIE;
66
67
68
	}
      break;
    case KEX_STATE_IGNORE:
Niels Möller's avatar
Niels Möller committed
69
      debug("handle_connection: Ignoring packet %d\n", msg);
70
71
72
73
74
75

      /* It's concievable with key exchange methods for which one
       * wants to switch to the NEWKEYS state immediately. But for
       * now, we always switch to the IN_PROGRESS state, to wait for a
       * KEXDH_INIT or KEXDH_REPLY message. */
      closure->kex_state = KEX_STATE_IN_PROGRESS;
76
      lsh_string_free(packet);
Niels Möller's avatar
Niels Möller committed
77
      return LSH_OK | LSH_GOON;
78
79
80
81
82

    case KEX_STATE_IN_PROGRESS:
      if ( (msg == SSH_MSG_NEWKEYS)
	   || (msg == SSH_MSG_KEXINIT))
	{
83
	  wwrite("Unexpected KEXINIT or NEWKEYS message!\n");
84
	  lsh_string_free(packet);
Niels Möller's avatar
Niels Möller committed
85
	  return LSH_FAIL | LSH_DIE;
86
87
88
	}
      break;
    case KEX_STATE_NEWKEYS:
Niels Möller's avatar
Niels Möller committed
89
90
      if ( (msg != SSH_MSG_NEWKEYS)
	   && (msg != SSH_MSG_DISCONNECT) )
91
	{
92
	  werror("Expected NEWKEYS message, but received message %d!\n",
93
		 msg);
94
	  lsh_string_free(packet);
Niels Möller's avatar
Niels Möller committed
95
	  return LSH_FAIL | LSH_DIE;
96
97
98
99
	}
      break;
    default:
      fatal("handle_connection: Internal error.\n");
100
    }
101

102
  return HANDLE_PACKET(closure->dispatch[msg], closure, packet);
103
104
}

105
static int do_fail(struct packet_handler *closure,
106
		   struct ssh_connection *connection UNUSED,
Niels Möller's avatar
Niels Möller committed
107
		   struct lsh_string *packet)
108
{
109
  CHECK_TYPE(packet_handler, closure);
Niels Möller's avatar
Niels Möller committed
110

111
  lsh_string_free(packet);
Niels Möller's avatar
Niels Möller committed
112
  return LSH_FAIL | LSH_DIE;
113
}
114

Niels Möller's avatar
Niels Möller committed
115
struct packet_handler *make_fail_handler(void)
116
{
117
  NEW(packet_handler, res);
118

119
120
  res->handler = do_fail;
  return res;
121
122
}

123
124
125
static int do_unimplemented(struct packet_handler *closure,
			    struct ssh_connection *connection,
			    struct lsh_string *packet)
126
{
Niels Möller's avatar
Niels Möller committed
127
  int res;
128
  CHECK_TYPE(packet_handler, closure);
Niels Möller's avatar
Niels Möller committed
129
130
131
132
133

  res =  A_WRITE(connection->write,
		 ssh_format("%c%i",
			    SSH_MSG_UNIMPLEMENTED,
			    packet->sequence_number));
134
  verbose("Received packet of unimplemented type %d.\n",
Niels Möller's avatar
Niels Möller committed
135
136
	  packet->data[0]);
  
137
138
139
  lsh_string_free(packet);
  return res;
}
140

Niels Möller's avatar
Niels Möller committed
141
struct packet_handler *make_unimplemented_handler(void)
142
{
143
  NEW(packet_handler, res);
144

145
146
  res->handler = do_unimplemented;
  return res;
147
148
149
}


150
151
152
153
struct ssh_connection *make_ssh_connection(struct packet_handler *kex_handler)
{
  int i;

154
155
  NEW(ssh_connection, connection);
  
156
  connection->super.write = handle_connection;
157
158
159
160
161
162

  /* Initialize instance variables */
  connection->client_version
    = connection->server_version
    = connection->session_id = NULL;

163
164
  connection->resources = empty_resource_list();
  
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
  connection->rec_max_packet = 0x8000;
  connection->rec_mac = NULL;
  connection->rec_crypto = NULL;

  connection->send_mac = NULL;
  connection->send_crypto = NULL;
  
  connection->kex_state = KEX_STATE_INIT;

  connection->kexinits[0]
    = connection->kexinits[1] = NULL;

  connection->literal_kexinits[0]
    = connection->literal_kexinits[1] = NULL;

  connection->newkeys = NULL;
181
182
  
  /* Initialize dispatch */
183
184
185
186
187
188
189
190
191
192
193
194
195
  connection->ignore = make_ignore_handler();
  connection->unimplemented = make_unimplemented_handler();
  connection->fail = make_fail_handler();
  
  for (i = 0; i < 0x100; i++)
    connection->dispatch[i] = connection->unimplemented;

  connection->dispatch[0] = connection->fail;
  connection->dispatch[SSH_MSG_DISCONNECT] = make_disconnect_handler();
  connection->dispatch[SSH_MSG_IGNORE] = connection->ignore;
  connection->dispatch[SSH_MSG_UNIMPLEMENTED] = connection->ignore;

  /* FIXME: Write a debug handler */
196
  connection->dispatch[SSH_MSG_DEBUG] = make_rec_debug_handler();
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229

  connection->dispatch[SSH_MSG_KEXINIT] = kex_handler;

  /* Make all other known message types terminate the connection */

  connection->dispatch[SSH_MSG_SERVICE_REQUEST] = connection->fail;
  connection->dispatch[SSH_MSG_SERVICE_ACCEPT] = connection->fail;
  connection->dispatch[SSH_MSG_NEWKEYS] = connection->fail;
  connection->dispatch[SSH_MSG_KEXDH_INIT] = connection->fail;
  connection->dispatch[SSH_MSG_KEXDH_REPLY] = connection->fail;
  connection->dispatch[SSH_MSG_USERAUTH_REQUEST] = connection->fail;
  connection->dispatch[SSH_MSG_USERAUTH_FAILURE] = connection->fail;
  connection->dispatch[SSH_MSG_USERAUTH_SUCCESS] = connection->fail;
  connection->dispatch[SSH_MSG_USERAUTH_BANNER] = connection->fail;
  connection->dispatch[SSH_MSG_USERAUTH_PK_OK] = connection->fail;
  connection->dispatch[SSH_MSG_USERAUTH_PASSWD_CHANGEREQ] = connection->fail;
  connection->dispatch[SSH_MSG_GLOBAL_REQUEST] = connection->fail;
  connection->dispatch[SSH_MSG_REQUEST_SUCCESS] = connection->fail;
  connection->dispatch[SSH_MSG_REQUEST_FAILURE] = connection->fail;
  connection->dispatch[SSH_MSG_CHANNEL_OPEN] = connection->fail;
  connection->dispatch[SSH_MSG_CHANNEL_OPEN_CONFIRMATION] = connection->fail;
  connection->dispatch[SSH_MSG_CHANNEL_OPEN_FAILURE] = connection->fail;
  connection->dispatch[SSH_MSG_CHANNEL_WINDOW_ADJUST] = connection->fail;
  connection->dispatch[SSH_MSG_CHANNEL_DATA] = connection->fail;
  connection->dispatch[SSH_MSG_CHANNEL_EXTENDED_DATA] = connection->fail;
  connection->dispatch[SSH_MSG_CHANNEL_EOF] = connection->fail;
  connection->dispatch[SSH_MSG_CHANNEL_CLOSE] = connection->fail;
  connection->dispatch[SSH_MSG_CHANNEL_REQUEST] = connection->fail;
  connection->dispatch[SSH_MSG_CHANNEL_SUCCESS] = connection->fail;
  connection->dispatch[SSH_MSG_CHANNEL_FAILURE] = connection->fail;
  
  return connection;
}
230
231
232
233
234
235
236

void connection_init_io(struct ssh_connection *connection,
			struct abstract_write *raw,
			struct randomness *r)
{
  /* Initialize i/o hooks */
  connection->raw = raw;
237
238
239
240
241
242
243
  connection->write = make_packet_deflate(
                        make_packet_pad(
                          make_packet_encrypt(raw, connection), 
                          connection,
                          r),
		        connection
		      );
244
245
246

  connection->send_crypto = connection->rec_crypto = NULL;
  connection->send_mac = connection->rec_mac = NULL;
247
  connection->send_compress = connection->rec_compress = NULL;
248
}