server.c 5.75 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1
/* server.c
2
 *
3
 */
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 1998 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.
Niels Möller's avatar
Niels Möller committed
22
23
24
25
26
 */

#include "server.h"

#include "abstract_io.h"
27
#include "channel.h"
28
#include "compress.h"
29
#include "connection.h"
Niels Möller's avatar
Niels Möller committed
30
31
#include "debug.h"
#include "format.h"
32
33
34
#include "keyexchange.h"
#include "read_line.h"
#include "read_packet.h"
Niels Möller's avatar
Niels Möller committed
35
#include "reaper.h"
36
37
#include "sexp.h"
#include "spki.h"
38
#include "ssh.h"
Niels Möller's avatar
Niels Möller committed
39
#include "unpad.h"
Niels Möller's avatar
Niels Möller committed
40
41
#include "werror.h"
#include "xalloc.h"
Niels Möller's avatar
Niels Möller committed
42

43
#include <assert.h>
44
/* #include <string.h> */
45
46
#include <errno.h>

47
48
#include <unistd.h>
#include <fcntl.h>
Niels Möller's avatar
Niels Möller committed
49

50
51
#include "server.c.x"

52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

static struct lsh_string *
format_service_accept(int name)
{
  return ssh_format("%c%a", SSH_MSG_SERVICE_ACCEPT, name);
}

#if DATAFELLOWS_WORKAROUNDS	      
static struct lsh_string *
format_service_accept_kludge(void)
{
  return ssh_format("%c", SSH_MSG_SERVICE_ACCEPT);
}
#endif /* DATAFELLOWS_WORKAROUNDS */


68
69
70
71
72
73
/* GABA:
   (class
     (name service_handler)
     (super packet_handler)
     (vars
       (services object alist)
74
75
       (c object command_continuation)
       (e object exception_handler)))
76
77
*/

Niels Möller's avatar
Niels Möller committed
78
79
80
81
static void
do_service_request(struct packet_handler *c,
		   struct ssh_connection *connection,
		   struct lsh_string *packet)
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
{
  CAST(service_handler, closure, c);

  struct simple_buffer buffer;
  unsigned msg_number;
  int name;
  
  simple_buffer_init(&buffer, packet->length, packet->data);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_SERVICE_REQUEST)
      && parse_atom(&buffer, &name)
      && parse_eod(&buffer))
    {
      if (name)
	{
	  CAST_SUBTYPE(command, service, ALIST_GET(closure->services, name));
	  if (service)
	    {
	      /* Don't accept any further service requests */
	      connection->dispatch[SSH_MSG_SERVICE_REQUEST]
103
		= &connection_fail_handler;
104
105

	      /* Start service */
106
107
108
109
110
111
112
#if DATAFELLOWS_WORKAROUNDS
	      if (connection->peer_flags & PEER_SERVICE_ACCEPT_KLUDGE)
		C_WRITE(connection, format_service_accept_kludge());
	      else
#endif /* DATAFELLOWS_WORKAROUNDS */
		C_WRITE(connection, format_service_accept(name));
	      
Niels Möller's avatar
Niels Möller committed
113
114
	      COMMAND_CALL(service, connection,
			   closure->c, closure->e);
Niels Möller's avatar
Niels Möller committed
115
	      return;
116
117
	    }
	}
Niels Möller's avatar
Niels Möller committed
118
119
120
121
122
      EXCEPTION_RAISE(connection->e,
		      make_protocol_exception(SSH_DISCONNECT_SERVICE_NOT_AVAILABLE, NULL));
      
    }
  else
123
    PROTOCOL_ERROR(connection->e, "Invalid SERVICE_REQUEST message");
124
}
Niels Möller's avatar
Niels Möller committed
125

126
static struct packet_handler *
127
make_service_request_handler(struct alist *services,
128
129
			     struct command_continuation *c,
			     struct exception_handler *e)
130
131
132
133
134
135
{
  NEW(service_handler, self);

  self->super.handler = do_service_request;
  self->services = services;
  self->c = c;
136
137
  self->e = e;
  
138
139
140
141
142
143
144
145
146
147
148
149
  return &self->super;
}

     
/* GABA:
   (class
     (name offer_service)
     (super command)
     (vars
       (services object alist)))
*/

Niels Möller's avatar
Niels Möller committed
150
151
152
153
154
static void
do_offer_service(struct command *s,
		 struct lsh_object *x,
		 struct command_continuation *c,
		 struct exception_handler *e)
155
156
157
158
159
{
  CAST(offer_service, self, s);
  CAST(ssh_connection, connection, x);

  connection->dispatch[SSH_MSG_SERVICE_REQUEST]
160
    = make_service_request_handler(self->services, c, e);
161
162
163
164
165
166
167
168
169
170
171
172
}

struct command *make_offer_service(struct alist *services)
{
  NEW(offer_service, self);

  self->super.call = do_offer_service;
  self->services = services;

  return &self->super;
}

173
174
/* Read server's private key */
/* Used by both lshd.c and lsh_proxy.c */
175

176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
static void
add_key(struct alist *keys,
        struct keypair *key)
{
  if (ALIST_GET(keys, key->type))
    werror("Multiple host keys for algorithm %a\n", key->type);
  ALIST_SET(keys, key->type, &key->super);
}

int
read_host_key(const char *file,
              struct alist *signature_algorithms,
              struct alist *keys)
{
  int fd = open(file, O_RDONLY);
  struct lsh_string *contents;
  struct signer *s;
  struct verifier *v;
  struct lsh_string *spki_public;
  
  int algorithm_name;

198
  if (fd < 0)
199
    {
200
      werror("Failed to open `%z' for reading %e\n", file, errno);
201
202
      return 0;
    }
203
  
204
205
206
  contents = io_read_file_raw(fd, 5000);
  if (!contents)
    {
207
      werror("Failed to read host key file `%z': %e\n", file, errno);
208
209
210
211
212
      close(fd);
      return 0;
    }
  close(fd);

213
214
215
  s = spki_make_signer(signature_algorithms,
		       contents,
		       &algorithm_name);
216
217
  lsh_string_free(contents);
  
218
219
220
221
222
223
224
225
226
  if (!s)
    {
      werror("Invalid host key\n");
      return 0;
    }

  v = SIGNER_GET_VERIFIER(s);
  assert(v);

227
  spki_public = PUBLIC_SPKI_KEY(v, 0);
228
229
230
231
232
233
234
235
236
237
  
  switch (algorithm_name)
    {
    case ATOM_DSA:
      add_key(keys,
              make_keypair(ATOM_SSH_DSS, PUBLIC_KEY(v), s));
      add_key(keys,
              make_keypair(ATOM_SPKI_SIGN_DSS, spki_public, s));
      break;

238
    case ATOM_RSA_PKCS1:
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
    case ATOM_RSA_PKCS1_SHA1:
      add_key(keys,
              make_keypair(ATOM_SSH_RSA, PUBLIC_KEY(v), s));
      /* Fall through */

    case ATOM_RSA_PKCS1_MD5:
      add_key(keys,
              make_keypair(ATOM_SPKI_SIGN_RSA, spki_public, s));
      break;

    default:
      werror("read_host_key: Unexpected algorithm %a.\n", algorithm_name);
      lsh_string_free(spki_public);
    }
  return 1;
}