GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ssh/sshd/../serverloop.c Lines: 0 399 0.0 %
Date: 2017-11-07 Branches: 0 224 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: serverloop.c,v 1.198 2017/09/12 06:35:32 djm Exp $ */
2
/*
3
 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4
 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5
 *                    All rights reserved
6
 * Server main loop for handling the interactive session.
7
 *
8
 * As far as I am concerned, the code I have written for this software
9
 * can be used freely for any purpose.  Any derived versions of this
10
 * software must be clearly marked as such, and if the derived work is
11
 * incompatible with the protocol description in the RFC file, it must be
12
 * called by a name other than "ssh" or "Secure Shell".
13
 *
14
 * SSH2 support by Markus Friedl.
15
 * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
16
 *
17
 * Redistribution and use in source and binary forms, with or without
18
 * modification, are permitted provided that the following conditions
19
 * are met:
20
 * 1. Redistributions of source code must retain the above copyright
21
 *    notice, this list of conditions and the following disclaimer.
22
 * 2. Redistributions in binary form must reproduce the above copyright
23
 *    notice, this list of conditions and the following disclaimer in the
24
 *    documentation and/or other materials provided with the distribution.
25
 *
26
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
 */
37
38
#include <sys/types.h>
39
#include <sys/wait.h>
40
#include <sys/socket.h>
41
#include <sys/time.h>
42
#include <sys/queue.h>
43
44
#include <netinet/in.h>
45
46
#include <errno.h>
47
#include <fcntl.h>
48
#include <pwd.h>
49
#include <signal.h>
50
#include <string.h>
51
#include <termios.h>
52
#include <unistd.h>
53
#include <stdarg.h>
54
55
#include "xmalloc.h"
56
#include "packet.h"
57
#include "buffer.h"
58
#include "log.h"
59
#include "misc.h"
60
#include "servconf.h"
61
#include "canohost.h"
62
#include "sshpty.h"
63
#include "channels.h"
64
#include "compat.h"
65
#include "ssh2.h"
66
#include "key.h"
67
#include "cipher.h"
68
#include "kex.h"
69
#include "hostfile.h"
70
#include "auth.h"
71
#include "session.h"
72
#include "dispatch.h"
73
#include "auth-options.h"
74
#include "serverloop.h"
75
#include "ssherr.h"
76
77
extern ServerOptions options;
78
79
/* XXX */
80
extern Authctxt *the_authctxt;
81
extern int use_privsep;
82
83
static int no_more_sessions = 0; /* Disallow further sessions. */
84
85
/*
86
 * This SIGCHLD kludge is used to detect when the child exits.  The server
87
 * will exit after that, as soon as forwarded connections have terminated.
88
 */
89
90
static volatile sig_atomic_t child_terminated = 0;	/* The child has terminated. */
91
92
/* Cleanup on signals (!use_privsep case only) */
93
static volatile sig_atomic_t received_sigterm = 0;
94
95
/* prototypes */
96
static void server_init_dispatch(void);
97
98
/*
99
 * we write to this pipe if a SIGCHLD is caught in order to avoid
100
 * the race between select() and child_terminated
101
 */
102
static int notify_pipe[2];
103
static void
104
notify_setup(void)
105
{
106
	if (pipe(notify_pipe) < 0) {
107
		error("pipe(notify_pipe) failed %s", strerror(errno));
108
	} else if ((fcntl(notify_pipe[0], F_SETFD, FD_CLOEXEC) == -1) ||
109
	    (fcntl(notify_pipe[1], F_SETFD, FD_CLOEXEC) == -1)) {
110
		error("fcntl(notify_pipe, F_SETFD) failed %s", strerror(errno));
111
		close(notify_pipe[0]);
112
		close(notify_pipe[1]);
113
	} else {
114
		set_nonblock(notify_pipe[0]);
115
		set_nonblock(notify_pipe[1]);
116
		return;
117
	}
118
	notify_pipe[0] = -1;	/* read end */
119
	notify_pipe[1] = -1;	/* write end */
120
}
121
static void
122
notify_parent(void)
123
{
124
	if (notify_pipe[1] != -1)
125
		(void)write(notify_pipe[1], "", 1);
126
}
127
static void
128
notify_prepare(fd_set *readset)
129
{
130
	if (notify_pipe[0] != -1)
131
		FD_SET(notify_pipe[0], readset);
132
}
133
static void
134
notify_done(fd_set *readset)
135
{
136
	char c;
137
138
	if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset))
139
		while (read(notify_pipe[0], &c, 1) != -1)
140
			debug2("notify_done: reading");
141
}
142
143
/*ARGSUSED*/
144
static void
145
sigchld_handler(int sig)
146
{
147
	int save_errno = errno;
148
	child_terminated = 1;
149
	signal(SIGCHLD, sigchld_handler);
150
	notify_parent();
151
	errno = save_errno;
152
}
153
154
/*ARGSUSED*/
155
static void
156
sigterm_handler(int sig)
157
{
158
	received_sigterm = sig;
159
}
160
161
static void
162
client_alive_check(struct ssh *ssh)
163
{
164
	int channel_id;
165
166
	/* timeout, check to see how many we have had */
167
	if (packet_inc_alive_timeouts() > options.client_alive_count_max) {
168
		logit("Timeout, client not responding.");
169
		cleanup_exit(255);
170
	}
171
172
	/*
173
	 * send a bogus global/channel request with "wantreply",
174
	 * we should get back a failure
175
	 */
176
	if ((channel_id = channel_find_open(ssh)) == -1) {
177
		packet_start(SSH2_MSG_GLOBAL_REQUEST);
178
		packet_put_cstring("keepalive@openssh.com");
179
		packet_put_char(1);	/* boolean: want reply */
180
	} else {
181
		channel_request_start(ssh, channel_id,
182
		    "keepalive@openssh.com", 1);
183
	}
184
	packet_send();
185
}
186
187
/*
188
 * Sleep in select() until we can do something.  This will initialize the
189
 * select masks.  Upon return, the masks will indicate which descriptors
190
 * have data or can accept data.  Optionally, a maximum time can be specified
191
 * for the duration of the wait (0 = infinite).
192
 */
193
static void
194
wait_until_can_do_something(struct ssh *ssh,
195
    int connection_in, int connection_out,
196
    fd_set **readsetp, fd_set **writesetp, int *maxfdp,
197
    u_int *nallocp, u_int64_t max_time_ms)
198
{
199
	struct timeval tv, *tvp;
200
	int ret;
201
	time_t minwait_secs = 0;
202
	int client_alive_scheduled = 0;
203
	static time_t last_client_time;
204
205
	/* Allocate and update select() masks for channel descriptors. */
206
	channel_prepare_select(ssh, readsetp, writesetp, maxfdp,
207
	    nallocp, &minwait_secs);
208
209
	/* XXX need proper deadline system for rekey/client alive */
210
	if (minwait_secs != 0)
211
		max_time_ms = MINIMUM(max_time_ms, (u_int)minwait_secs * 1000);
212
213
	/*
214
	 * if using client_alive, set the max timeout accordingly,
215
	 * and indicate that this particular timeout was for client
216
	 * alive by setting the client_alive_scheduled flag.
217
	 *
218
	 * this could be randomized somewhat to make traffic
219
	 * analysis more difficult, but we're not doing it yet.
220
	 */
221
	if (options.client_alive_interval) {
222
		uint64_t keepalive_ms =
223
		    (uint64_t)options.client_alive_interval * 1000;
224
225
		client_alive_scheduled = 1;
226
		if (max_time_ms == 0 || max_time_ms > keepalive_ms)
227
			max_time_ms = keepalive_ms;
228
	}
229
230
#if 0
231
	/* wrong: bad condition XXX */
232
	if (channel_not_very_much_buffered_data())
233
#endif
234
	FD_SET(connection_in, *readsetp);
235
	notify_prepare(*readsetp);
236
237
	/*
238
	 * If we have buffered packet data going to the client, mark that
239
	 * descriptor.
240
	 */
241
	if (packet_have_data_to_write())
242
		FD_SET(connection_out, *writesetp);
243
244
	/*
245
	 * If child has terminated and there is enough buffer space to read
246
	 * from it, then read as much as is available and exit.
247
	 */
248
	if (child_terminated && packet_not_very_much_data_to_write())
249
		if (max_time_ms == 0 || client_alive_scheduled)
250
			max_time_ms = 100;
251
252
	if (max_time_ms == 0)
253
		tvp = NULL;
254
	else {
255
		tv.tv_sec = max_time_ms / 1000;
256
		tv.tv_usec = 1000 * (max_time_ms % 1000);
257
		tvp = &tv;
258
	}
259
260
	/* Wait for something to happen, or the timeout to expire. */
261
	ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
262
263
	if (ret == -1) {
264
		memset(*readsetp, 0, *nallocp);
265
		memset(*writesetp, 0, *nallocp);
266
		if (errno != EINTR)
267
			error("select: %.100s", strerror(errno));
268
	} else if (client_alive_scheduled) {
269
		time_t now = monotime();
270
271
		if (ret == 0) { /* timeout */
272
			client_alive_check(ssh);
273
		} else if (FD_ISSET(connection_in, *readsetp)) {
274
			last_client_time = now;
275
		} else if (last_client_time != 0 && last_client_time +
276
		    options.client_alive_interval <= now) {
277
			client_alive_check(ssh);
278
			last_client_time = now;
279
		}
280
	}
281
282
	notify_done(*readsetp);
283
}
284
285
/*
286
 * Processes input from the client and the program.  Input data is stored
287
 * in buffers and processed later.
288
 */
289
static int
290
process_input(struct ssh *ssh, fd_set *readset, int connection_in)
291
{
292
	int len;
293
	char buf[16384];
294
295
	/* Read and buffer any input data from the client. */
296
	if (FD_ISSET(connection_in, readset)) {
297
		len = read(connection_in, buf, sizeof(buf));
298
		if (len == 0) {
299
			verbose("Connection closed by %.100s port %d",
300
			    ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
301
			return -1;
302
		} else if (len < 0) {
303
			if (errno != EINTR && errno != EAGAIN) {
304
				verbose("Read error from remote host "
305
				    "%.100s port %d: %.100s",
306
				    ssh_remote_ipaddr(ssh),
307
				    ssh_remote_port(ssh), strerror(errno));
308
				cleanup_exit(255);
309
			}
310
		} else {
311
			/* Buffer any received data. */
312
			packet_process_incoming(buf, len);
313
		}
314
	}
315
	return 0;
316
}
317
318
/*
319
 * Sends data from internal buffers to client program stdin.
320
 */
321
static void
322
process_output(fd_set *writeset, int connection_out)
323
{
324
	/* Send any buffered packet data to the client. */
325
	if (FD_ISSET(connection_out, writeset))
326
		packet_write_poll();
327
}
328
329
static void
330
process_buffered_input_packets(struct ssh *ssh)
331
{
332
	ssh_dispatch_run_fatal(ssh, DISPATCH_NONBLOCK, NULL);
333
}
334
335
static void
336
collect_children(struct ssh *ssh)
337
{
338
	pid_t pid;
339
	sigset_t oset, nset;
340
	int status;
341
342
	/* block SIGCHLD while we check for dead children */
343
	sigemptyset(&nset);
344
	sigaddset(&nset, SIGCHLD);
345
	sigprocmask(SIG_BLOCK, &nset, &oset);
346
	if (child_terminated) {
347
		debug("Received SIGCHLD.");
348
		while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
349
		    (pid < 0 && errno == EINTR))
350
			if (pid > 0)
351
				session_close_by_pid(ssh, pid, status);
352
		child_terminated = 0;
353
	}
354
	sigprocmask(SIG_SETMASK, &oset, NULL);
355
}
356
357
void
358
server_loop2(struct ssh *ssh, Authctxt *authctxt)
359
{
360
	fd_set *readset = NULL, *writeset = NULL;
361
	int max_fd;
362
	u_int nalloc = 0, connection_in, connection_out;
363
	u_int64_t rekey_timeout_ms = 0;
364
365
	debug("Entering interactive session for SSH2.");
366
367
	signal(SIGCHLD, sigchld_handler);
368
	child_terminated = 0;
369
	connection_in = packet_get_connection_in();
370
	connection_out = packet_get_connection_out();
371
372
	if (!use_privsep) {
373
		signal(SIGTERM, sigterm_handler);
374
		signal(SIGINT, sigterm_handler);
375
		signal(SIGQUIT, sigterm_handler);
376
	}
377
378
	notify_setup();
379
380
	max_fd = MAXIMUM(connection_in, connection_out);
381
	max_fd = MAXIMUM(max_fd, notify_pipe[0]);
382
383
	server_init_dispatch();
384
385
	for (;;) {
386
		process_buffered_input_packets(ssh);
387
388
		if (!ssh_packet_is_rekeying(ssh) &&
389
		    packet_not_very_much_data_to_write())
390
			channel_output_poll(ssh);
391
		if (options.rekey_interval > 0 && !ssh_packet_is_rekeying(ssh))
392
			rekey_timeout_ms = packet_get_rekey_timeout() * 1000;
393
		else
394
			rekey_timeout_ms = 0;
395
396
		wait_until_can_do_something(ssh, connection_in, connection_out,
397
		    &readset, &writeset, &max_fd, &nalloc, rekey_timeout_ms);
398
399
		if (received_sigterm) {
400
			logit("Exiting on signal %d", (int)received_sigterm);
401
			/* Clean up sessions, utmp, etc. */
402
			cleanup_exit(255);
403
		}
404
405
		collect_children(ssh);
406
		if (!ssh_packet_is_rekeying(ssh))
407
			channel_after_select(ssh, readset, writeset);
408
		if (process_input(ssh, readset, connection_in) < 0)
409
			break;
410
		process_output(writeset, connection_out);
411
	}
412
	collect_children(ssh);
413
414
	free(readset);
415
	free(writeset);
416
417
	/* free all channels, no more reads and writes */
418
	channel_free_all(ssh);
419
420
	/* free remaining sessions, e.g. remove wtmp entries */
421
	session_destroy_all(ssh, NULL);
422
}
423
424
static int
425
server_input_keep_alive(int type, u_int32_t seq, struct ssh *ssh)
426
{
427
	debug("Got %d/%u for keepalive", type, seq);
428
	/*
429
	 * reset timeout, since we got a sane answer from the client.
430
	 * even if this was generated by something other than
431
	 * the bogus CHANNEL_REQUEST we send for keepalives.
432
	 */
433
	packet_set_alive_timeouts(0);
434
	return 0;
435
}
436
437
static Channel *
438
server_request_direct_tcpip(struct ssh *ssh, int *reason, const char **errmsg)
439
{
440
	Channel *c = NULL;
441
	char *target, *originator;
442
	u_short target_port, originator_port;
443
444
	target = packet_get_string(NULL);
445
	target_port = packet_get_int();
446
	originator = packet_get_string(NULL);
447
	originator_port = packet_get_int();
448
	packet_check_eom();
449
450
	debug("server_request_direct_tcpip: originator %s port %d, target %s "
451
	    "port %d", originator, originator_port, target, target_port);
452
453
	/* XXX fine grained permissions */
454
	if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0 &&
455
	    !no_port_forwarding_flag && !options.disable_forwarding) {
456
		c = channel_connect_to_port(ssh, target, target_port,
457
		    "direct-tcpip", "direct-tcpip", reason, errmsg);
458
	} else {
459
		logit("refused local port forward: "
460
		    "originator %s port %d, target %s port %d",
461
		    originator, originator_port, target, target_port);
462
		if (reason != NULL)
463
			*reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED;
464
	}
465
466
	free(originator);
467
	free(target);
468
469
	return c;
470
}
471
472
static Channel *
473
server_request_direct_streamlocal(struct ssh *ssh)
474
{
475
	Channel *c = NULL;
476
	char *target, *originator;
477
	u_short originator_port;
478
	struct passwd *pw = the_authctxt->pw;
479
480
	if (pw == NULL || !the_authctxt->valid)
481
		fatal("server_input_global_request: no/invalid user");
482
483
	target = packet_get_string(NULL);
484
	originator = packet_get_string(NULL);
485
	originator_port = packet_get_int();
486
	packet_check_eom();
487
488
	debug("server_request_direct_streamlocal: originator %s port %d, target %s",
489
	    originator, originator_port, target);
490
491
	/* XXX fine grained permissions */
492
	if ((options.allow_streamlocal_forwarding & FORWARD_LOCAL) != 0 &&
493
	    !no_port_forwarding_flag && !options.disable_forwarding &&
494
	    (pw->pw_uid == 0 || use_privsep)) {
495
		c = channel_connect_to_path(ssh, target,
496
		    "direct-streamlocal@openssh.com", "direct-streamlocal");
497
	} else {
498
		logit("refused streamlocal port forward: "
499
		    "originator %s port %d, target %s",
500
		    originator, originator_port, target);
501
	}
502
503
	free(originator);
504
	free(target);
505
506
	return c;
507
}
508
509
static Channel *
510
server_request_tun(struct ssh *ssh)
511
{
512
	Channel *c = NULL;
513
	int mode, tun;
514
	int sock;
515
516
	mode = packet_get_int();
517
	switch (mode) {
518
	case SSH_TUNMODE_POINTOPOINT:
519
	case SSH_TUNMODE_ETHERNET:
520
		break;
521
	default:
522
		packet_send_debug("Unsupported tunnel device mode.");
523
		return NULL;
524
	}
525
	if ((options.permit_tun & mode) == 0) {
526
		packet_send_debug("Server has rejected tunnel device "
527
		    "forwarding");
528
		return NULL;
529
	}
530
531
	tun = packet_get_int();
532
	if (forced_tun_device != -1) {
533
		if (tun != SSH_TUNID_ANY && forced_tun_device != tun)
534
			goto done;
535
		tun = forced_tun_device;
536
	}
537
	sock = tun_open(tun, mode);
538
	if (sock < 0)
539
		goto done;
540
	c = channel_new(ssh, "tun", SSH_CHANNEL_OPEN, sock, sock, -1,
541
	    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
542
	c->datagram = 1;
543
544
 done:
545
	if (c == NULL)
546
		packet_send_debug("Failed to open the tunnel device.");
547
	return c;
548
}
549
550
static Channel *
551
server_request_session(struct ssh *ssh)
552
{
553
	Channel *c;
554
555
	debug("input_session_request");
556
	packet_check_eom();
557
558
	if (no_more_sessions) {
559
		packet_disconnect("Possible attack: attempt to open a session "
560
		    "after additional sessions disabled");
561
	}
562
563
	/*
564
	 * A server session has no fd to read or write until a
565
	 * CHANNEL_REQUEST for a shell is made, so we set the type to
566
	 * SSH_CHANNEL_LARVAL.  Additionally, a callback for handling all
567
	 * CHANNEL_REQUEST messages is registered.
568
	 */
569
	c = channel_new(ssh, "session", SSH_CHANNEL_LARVAL,
570
	    -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT,
571
	    0, "server-session", 1);
572
	if (session_open(the_authctxt, c->self) != 1) {
573
		debug("session open failed, free channel %d", c->self);
574
		channel_free(ssh, c);
575
		return NULL;
576
	}
577
	channel_register_cleanup(ssh, c->self, session_close_by_channel, 0);
578
	return c;
579
}
580
581
static int
582
server_input_channel_open(int type, u_int32_t seq, struct ssh *ssh)
583
{
584
	Channel *c = NULL;
585
	char *ctype;
586
	const char *errmsg = NULL;
587
	int rchan, reason = SSH2_OPEN_CONNECT_FAILED;
588
	u_int rmaxpack, rwindow, len;
589
590
	ctype = packet_get_string(&len);
591
	rchan = packet_get_int();
592
	rwindow = packet_get_int();
593
	rmaxpack = packet_get_int();
594
595
	debug("server_input_channel_open: ctype %s rchan %d win %d max %d",
596
	    ctype, rchan, rwindow, rmaxpack);
597
598
	if (strcmp(ctype, "session") == 0) {
599
		c = server_request_session(ssh);
600
	} else if (strcmp(ctype, "direct-tcpip") == 0) {
601
		c = server_request_direct_tcpip(ssh, &reason, &errmsg);
602
	} else if (strcmp(ctype, "direct-streamlocal@openssh.com") == 0) {
603
		c = server_request_direct_streamlocal(ssh);
604
	} else if (strcmp(ctype, "tun@openssh.com") == 0) {
605
		c = server_request_tun(ssh);
606
	}
607
	if (c != NULL) {
608
		debug("server_input_channel_open: confirm %s", ctype);
609
		c->remote_id = rchan;
610
		c->have_remote_id = 1;
611
		c->remote_window = rwindow;
612
		c->remote_maxpacket = rmaxpack;
613
		if (c->type != SSH_CHANNEL_CONNECTING) {
614
			packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
615
			packet_put_int(c->remote_id);
616
			packet_put_int(c->self);
617
			packet_put_int(c->local_window);
618
			packet_put_int(c->local_maxpacket);
619
			packet_send();
620
		}
621
	} else {
622
		debug("server_input_channel_open: failure %s", ctype);
623
		packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
624
		packet_put_int(rchan);
625
		packet_put_int(reason);
626
		if (!(datafellows & SSH_BUG_OPENFAILURE)) {
627
			packet_put_cstring(errmsg ? errmsg : "open failed");
628
			packet_put_cstring("");
629
		}
630
		packet_send();
631
	}
632
	free(ctype);
633
	return 0;
634
}
635
636
static int
637
server_input_hostkeys_prove(struct ssh *ssh, struct sshbuf **respp)
638
{
639
	struct sshbuf *resp = NULL;
640
	struct sshbuf *sigbuf = NULL;
641
	struct sshkey *key = NULL, *key_pub = NULL, *key_prv = NULL;
642
	int r, ndx, success = 0;
643
	const u_char *blob;
644
	u_char *sig = 0;
645
	size_t blen, slen;
646
647
	if ((resp = sshbuf_new()) == NULL || (sigbuf = sshbuf_new()) == NULL)
648
		fatal("%s: sshbuf_new", __func__);
649
650
	while (ssh_packet_remaining(ssh) > 0) {
651
		sshkey_free(key);
652
		key = NULL;
653
		if ((r = sshpkt_get_string_direct(ssh, &blob, &blen)) != 0 ||
654
		    (r = sshkey_from_blob(blob, blen, &key)) != 0) {
655
			error("%s: couldn't parse key: %s",
656
			    __func__, ssh_err(r));
657
			goto out;
658
		}
659
		/*
660
		 * Better check that this is actually one of our hostkeys
661
		 * before attempting to sign anything with it.
662
		 */
663
		if ((ndx = ssh->kex->host_key_index(key, 1, ssh)) == -1) {
664
			error("%s: unknown host %s key",
665
			    __func__, sshkey_type(key));
666
			goto out;
667
		}
668
		/*
669
		 * XXX refactor: make kex->sign just use an index rather
670
		 * than passing in public and private keys
671
		 */
672
		if ((key_prv = get_hostkey_by_index(ndx)) == NULL &&
673
		    (key_pub = get_hostkey_public_by_index(ndx, ssh)) == NULL) {
674
			error("%s: can't retrieve hostkey %d", __func__, ndx);
675
			goto out;
676
		}
677
		sshbuf_reset(sigbuf);
678
		free(sig);
679
		sig = NULL;
680
		if ((r = sshbuf_put_cstring(sigbuf,
681
		    "hostkeys-prove-00@openssh.com")) != 0 ||
682
		    (r = sshbuf_put_string(sigbuf,
683
		    ssh->kex->session_id, ssh->kex->session_id_len)) != 0 ||
684
		    (r = sshkey_puts(key, sigbuf)) != 0 ||
685
		    (r = ssh->kex->sign(key_prv, key_pub, &sig, &slen,
686
		    sshbuf_ptr(sigbuf), sshbuf_len(sigbuf), NULL, 0)) != 0 ||
687
		    (r = sshbuf_put_string(resp, sig, slen)) != 0) {
688
			error("%s: couldn't prepare signature: %s",
689
			    __func__, ssh_err(r));
690
			goto out;
691
		}
692
	}
693
	/* Success */
694
	*respp = resp;
695
	resp = NULL; /* don't free it */
696
	success = 1;
697
 out:
698
	free(sig);
699
	sshbuf_free(resp);
700
	sshbuf_free(sigbuf);
701
	sshkey_free(key);
702
	return success;
703
}
704
705
static int
706
server_input_global_request(int type, u_int32_t seq, struct ssh *ssh)
707
{
708
	char *rtype;
709
	int want_reply;
710
	int r, success = 0, allocated_listen_port = 0;
711
	struct sshbuf *resp = NULL;
712
	struct passwd *pw = the_authctxt->pw;
713
714
	if (pw == NULL || !the_authctxt->valid)
715
		fatal("server_input_global_request: no/invalid user");
716
717
	rtype = packet_get_string(NULL);
718
	want_reply = packet_get_char();
719
	debug("server_input_global_request: rtype %s want_reply %d", rtype, want_reply);
720
721
	/* -R style forwarding */
722
	if (strcmp(rtype, "tcpip-forward") == 0) {
723
		struct Forward fwd;
724
725
		memset(&fwd, 0, sizeof(fwd));
726
		fwd.listen_host = packet_get_string(NULL);
727
		fwd.listen_port = (u_short)packet_get_int();
728
		debug("server_input_global_request: tcpip-forward listen %s port %d",
729
		    fwd.listen_host, fwd.listen_port);
730
731
		/* check permissions */
732
		if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0 ||
733
		    no_port_forwarding_flag || options.disable_forwarding ||
734
		    (!want_reply && fwd.listen_port == 0) ||
735
		    (fwd.listen_port != 0 &&
736
		     !bind_permitted(fwd.listen_port, pw->pw_uid))) {
737
			success = 0;
738
			packet_send_debug("Server has disabled port forwarding.");
739
		} else {
740
			/* Start listening on the port */
741
			success = channel_setup_remote_fwd_listener(ssh, &fwd,
742
			    &allocated_listen_port, &options.fwd_opts);
743
		}
744
		free(fwd.listen_host);
745
		if ((resp = sshbuf_new()) == NULL)
746
			fatal("%s: sshbuf_new", __func__);
747
		if (allocated_listen_port != 0 &&
748
		    (r = sshbuf_put_u32(resp, allocated_listen_port)) != 0)
749
			fatal("%s: sshbuf_put_u32: %s", __func__, ssh_err(r));
750
	} else if (strcmp(rtype, "cancel-tcpip-forward") == 0) {
751
		struct Forward fwd;
752
753
		memset(&fwd, 0, sizeof(fwd));
754
		fwd.listen_host = packet_get_string(NULL);
755
		fwd.listen_port = (u_short)packet_get_int();
756
		debug("%s: cancel-tcpip-forward addr %s port %d", __func__,
757
		    fwd.listen_host, fwd.listen_port);
758
759
		success = channel_cancel_rport_listener(ssh, &fwd);
760
		free(fwd.listen_host);
761
	} else if (strcmp(rtype, "streamlocal-forward@openssh.com") == 0) {
762
		struct Forward fwd;
763
764
		memset(&fwd, 0, sizeof(fwd));
765
		fwd.listen_path = packet_get_string(NULL);
766
		debug("server_input_global_request: streamlocal-forward listen path %s",
767
		    fwd.listen_path);
768
769
		/* check permissions */
770
		if ((options.allow_streamlocal_forwarding & FORWARD_REMOTE) == 0
771
		    || no_port_forwarding_flag || options.disable_forwarding ||
772
		    (pw->pw_uid != 0 && !use_privsep)) {
773
			success = 0;
774
			packet_send_debug("Server has disabled "
775
			    "streamlocal forwarding.");
776
		} else {
777
			/* Start listening on the socket */
778
			success = channel_setup_remote_fwd_listener(ssh,
779
			    &fwd, NULL, &options.fwd_opts);
780
		}
781
		free(fwd.listen_path);
782
	} else if (strcmp(rtype, "cancel-streamlocal-forward@openssh.com") == 0) {
783
		struct Forward fwd;
784
785
		memset(&fwd, 0, sizeof(fwd));
786
		fwd.listen_path = packet_get_string(NULL);
787
		debug("%s: cancel-streamlocal-forward path %s", __func__,
788
		    fwd.listen_path);
789
790
		success = channel_cancel_rport_listener(ssh, &fwd);
791
		free(fwd.listen_path);
792
	} else if (strcmp(rtype, "no-more-sessions@openssh.com") == 0) {
793
		no_more_sessions = 1;
794
		success = 1;
795
	} else if (strcmp(rtype, "hostkeys-prove-00@openssh.com") == 0) {
796
		success = server_input_hostkeys_prove(ssh, &resp);
797
	}
798
	if (want_reply) {
799
		packet_start(success ?
800
		    SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
801
		if (success && resp != NULL)
802
			ssh_packet_put_raw(ssh, sshbuf_ptr(resp),
803
			    sshbuf_len(resp));
804
		packet_send();
805
		packet_write_wait();
806
	}
807
	free(rtype);
808
	sshbuf_free(resp);
809
	return 0;
810
}
811
812
static int
813
server_input_channel_req(int type, u_int32_t seq, struct ssh *ssh)
814
{
815
	Channel *c;
816
	int id, reply, success = 0;
817
	char *rtype;
818
819
	id = packet_get_int();
820
	rtype = packet_get_string(NULL);
821
	reply = packet_get_char();
822
823
	debug("server_input_channel_req: channel %d request %s reply %d",
824
	    id, rtype, reply);
825
826
	if ((c = channel_lookup(ssh, id)) == NULL)
827
		packet_disconnect("server_input_channel_req: "
828
		    "unknown channel %d", id);
829
	if (!strcmp(rtype, "eow@openssh.com")) {
830
		packet_check_eom();
831
		chan_rcvd_eow(ssh, c);
832
	} else if ((c->type == SSH_CHANNEL_LARVAL ||
833
	    c->type == SSH_CHANNEL_OPEN) && strcmp(c->ctype, "session") == 0)
834
		success = session_input_channel_req(ssh, c, rtype);
835
	if (reply && !(c->flags & CHAN_CLOSE_SENT)) {
836
		if (!c->have_remote_id)
837
			fatal("%s: channel %d: no remote_id",
838
			    __func__, c->self);
839
		packet_start(success ?
840
		    SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
841
		packet_put_int(c->remote_id);
842
		packet_send();
843
	}
844
	free(rtype);
845
	return 0;
846
}
847
848
static void
849
server_init_dispatch(void)
850
{
851
	debug("server_init_dispatch");
852
	dispatch_init(&dispatch_protocol_error);
853
	dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose);
854
	dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data);
855
	dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof);
856
	dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data);
857
	dispatch_set(SSH2_MSG_CHANNEL_OPEN, &server_input_channel_open);
858
	dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
859
	dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
860
	dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &server_input_channel_req);
861
	dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
862
	dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request);
863
	/* client_alive */
864
	dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &server_input_keep_alive);
865
	dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_keep_alive);
866
	dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &server_input_keep_alive);
867
	dispatch_set(SSH2_MSG_REQUEST_FAILURE, &server_input_keep_alive);
868
	/* rekeying */
869
	dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
870
}