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

#include "connection.h"
6

7
#include "debug.h"
8
#include "encrypt.h"
9
#include "format.h"
10
#include "disconnect.h"
11
#include "keyexchange.h"
12
#include "packet_ignore.h"
13
#include "pad.h"
14
15
16
#include "ssh.h"
#include "werror.h"
#include "xalloc.h"
17

18
static int handle_connection(struct abstract_write **w,
19
			     struct lsh_string *packet)
20
{
21
  struct ssh_connection *closure = (struct ssh_connection *) *w;
22
  UINT8 msg;
Niels Möller's avatar
Niels Möller committed
23

24
25
26
27
28
  if (!packet->length)
    {
      werror("connection.c: Recieved empty packet!\n");
      return 0;
    }
29

30
  msg = packet->data[0];
31

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

  switch(closure->kex_state)
35
    {
36
37
38
39
    case KEX_STATE_INIT:
      if (msg == SSH_MSG_NEWKEYS)
	{
	  werror("Unexpected NEWKEYS message!\n");
40
	  lsh_string_free(packet);
Niels Möller's avatar
Niels Möller committed
41
	  return LSH_FAIL | LSH_DIE;
42
43
44
	}
      break;
    case KEX_STATE_IGNORE:
Niels Möller's avatar
Niels Möller committed
45
      debug("handle_connection: Ignoring packet %d\n", msg);
46
47
48
49
50
51

      /* 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;
52
      lsh_string_free(packet);
Niels Möller's avatar
Niels Möller committed
53
      return LSH_OK | LSH_GOON;
54
55
56
57
58
59

    case KEX_STATE_IN_PROGRESS:
      if ( (msg == SSH_MSG_NEWKEYS)
	   || (msg == SSH_MSG_KEXINIT))
	{
	  werror("Unexpected KEXINIT or NEWKEYS message!\n");
60
	  lsh_string_free(packet);
Niels Möller's avatar
Niels Möller committed
61
	  return LSH_FAIL | LSH_DIE;
62
63
64
	}
      break;
    case KEX_STATE_NEWKEYS:
Niels Möller's avatar
Niels Möller committed
65
66
      if ( (msg != SSH_MSG_NEWKEYS)
	   && (msg != SSH_MSG_DISCONNECT) )
67
68
69
	{
	  werror("Expected NEWKEYS message, but recieved message %d!\n",
		 msg);
70
	  lsh_string_free(packet);
Niels Möller's avatar
Niels Möller committed
71
	  return LSH_FAIL | LSH_DIE;
72
73
74
75
	}
      break;
    default:
      fatal("handle_connection: Internal error.\n");
76
    }
77

78
  return HANDLE_PACKET(closure->dispatch[msg], closure, packet);
79
80
}

81
static int do_fail(struct packet_handler *closure,
Niels Möller's avatar
Niels Möller committed
82
83
		   struct ssh_connection *connection,
		   struct lsh_string *packet)
84
{
Niels Möller's avatar
Niels Möller committed
85
86
  MDEBUG(closure);

87
  lsh_string_free(packet);
Niels Möller's avatar
Niels Möller committed
88
  return LSH_FAIL | LSH_DIE;
89
}
90

Niels Möller's avatar
Niels Möller committed
91
struct packet_handler *make_fail_handler(void)
92
{
Niels Möller's avatar
Niels Möller committed
93
94
95
  struct packet_handler *res;

  NEW(res);
96

97
98
  res->handler = do_fail;
  return res;
99
100
}

101
102
103
static int do_unimplemented(struct packet_handler *closure,
			    struct ssh_connection *connection,
			    struct lsh_string *packet)
104
{
Niels Möller's avatar
Niels Möller committed
105
106
107
108
109
110
111
112
  int res;

  MDEBUG(closure);

  res =  A_WRITE(connection->write,
		 ssh_format("%c%i",
			    SSH_MSG_UNIMPLEMENTED,
			    packet->sequence_number));
Niels Möller's avatar
Niels Möller committed
113
114
115
  verbose("Recieved packet of unimplemented type %d.\n",
	  packet->data[0]);
  
116
117
118
  lsh_string_free(packet);
  return res;
}
119

Niels Möller's avatar
Niels Möller committed
120
struct packet_handler *make_unimplemented_handler(void)
121
{
Niels Möller's avatar
Niels Möller committed
122
123
124
  struct packet_handler *res;

  NEW(res);
125

126
127
  res->handler = do_unimplemented;
  return res;
128
129
130
}


131
132
struct ssh_connection *make_ssh_connection(struct packet_handler *kex_handler)
{
Niels Möller's avatar
Niels Möller committed
133
  struct ssh_connection *connection;
134
135
  int i;

Niels Möller's avatar
Niels Möller committed
136
  NEW(connection);
137
  connection->super.write = handle_connection;
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159

  /* 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;
160
161
  
  /* Initialize dispatch */
162
163
164
165
166
167
168
169
170
171
172
173
174
  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 */
175
  connection->dispatch[SSH_MSG_DEBUG] = make_rec_debug_handler();
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208

  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;
}
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223

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;
}