connection.c 7.12 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 "packet_ignore.h"
32
#include "pad.h"
33
34
35
#include "ssh.h"
#include "werror.h"
#include "xalloc.h"
36

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

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

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

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

Niels Möller's avatar
Niels Möller committed
55
  debug("handle_connection: Recieved packet of type %d\n", msg);
56
57

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

      /* 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;
75
      lsh_string_free(packet);
Niels Möller's avatar
Niels Möller committed
76
      return LSH_OK | LSH_GOON;
77
78
79
80
81
82

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

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

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

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

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

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

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

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

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

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


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

153
154
  NEW(ssh_connection, connection);
  
155
  connection->super.write = handle_connection;
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177

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

  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;
178
179
  
  /* Initialize dispatch */
180
181
182
183
184
185
186
187
188
189
190
191
192
  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 */
193
  connection->dispatch[SSH_MSG_DEBUG] = make_rec_debug_handler();
194
195
196
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

  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;
}
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241

void connection_init_io(struct ssh_connection *connection,
			struct abstract_write *raw,
			struct randomness *r)
{
  /* Initialize i/o hooks */
  connection->raw = raw;
  connection->write = make_packet_pad(make_packet_encrypt(raw,
							  connection),
				      connection,
				      r);

  connection->send_crypto = connection->rec_crypto = NULL;
  connection->send_mac = connection->rec_mac = NULL;
}