1294336Sdes/* $OpenBSD: dispatch.c,v 1.27 2015/05/01 07:10:01 djm Exp $ */
260573Skris/*
360573Skris * Copyright (c) 2000 Markus Friedl.  All rights reserved.
460573Skris *
560573Skris * Redistribution and use in source and binary forms, with or without
660573Skris * modification, are permitted provided that the following conditions
760573Skris * are met:
860573Skris * 1. Redistributions of source code must retain the above copyright
960573Skris *    notice, this list of conditions and the following disclaimer.
1060573Skris * 2. Redistributions in binary form must reproduce the above copyright
1160573Skris *    notice, this list of conditions and the following disclaimer in the
1260573Skris *    documentation and/or other materials provided with the distribution.
1360573Skris *
1460573Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1560573Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1660573Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1760573Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1860573Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1960573Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2060573Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2160573Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2260573Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2360573Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2460573Skris */
25162852Sdes
2660573Skris#include "includes.h"
2776259Sgreen
28162852Sdes#include <sys/types.h>
29162852Sdes
30162852Sdes#include <signal.h>
31162852Sdes#include <stdarg.h>
32162852Sdes
3376259Sgreen#include "ssh1.h"
3476259Sgreen#include "ssh2.h"
3576259Sgreen#include "log.h"
3660573Skris#include "dispatch.h"
3760573Skris#include "packet.h"
3876259Sgreen#include "compat.h"
39294332Sdes#include "ssherr.h"
4060573Skris
41294332Sdesint
42294332Sdesdispatch_protocol_error(int type, u_int32_t seq, void *ctx)
43294332Sdes{
44294332Sdes	struct ssh *ssh = active_state; /* XXX */
45294332Sdes	int r;
4660573Skris
47124208Sdes	logit("dispatch_protocol_error: type %d seq %u", type, seq);
4892555Sdes	if (!compat20)
4992555Sdes		fatal("protocol error");
50294332Sdes	if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 ||
51294332Sdes	    (r = sshpkt_put_u32(ssh, seq)) != 0 ||
52294332Sdes	    (r = sshpkt_send(ssh)) != 0 ||
53294332Sdes	    (r = ssh_packet_write_wait(ssh)) != 0)
54294332Sdes		sshpkt_fatal(ssh, __func__, r);
55294332Sdes	return 0;
5660573Skris}
57294332Sdes
58294332Sdesint
59294332Sdesdispatch_protocol_ignore(int type, u_int32_t seq, void *ssh)
6092555Sdes{
61124208Sdes	logit("dispatch_protocol_ignore: type %d seq %u", type, seq);
62294332Sdes	return 0;
6392555Sdes}
64294332Sdes
6592555Sdesvoid
66294332Sdesssh_dispatch_init(struct ssh *ssh, dispatch_fn *dflt)
6760573Skris{
6892555Sdes	u_int i;
6960573Skris	for (i = 0; i < DISPATCH_MAX; i++)
70294332Sdes		ssh->dispatch[i] = dflt;
7160573Skris}
72294332Sdes
7360573Skrisvoid
74294332Sdesssh_dispatch_range(struct ssh *ssh, u_int from, u_int to, dispatch_fn *fn)
7592555Sdes{
7692555Sdes	u_int i;
7792555Sdes
7892555Sdes	for (i = from; i <= to; i++) {
7992555Sdes		if (i >= DISPATCH_MAX)
8092555Sdes			break;
81294332Sdes		ssh->dispatch[i] = fn;
8292555Sdes	}
8392555Sdes}
84294332Sdes
8592555Sdesvoid
86294332Sdesssh_dispatch_set(struct ssh *ssh, int type, dispatch_fn *fn)
8760573Skris{
88294332Sdes	ssh->dispatch[type] = fn;
8960573Skris}
90294332Sdes
91294332Sdesint
92294332Sdesssh_dispatch_run(struct ssh *ssh, int mode, volatile sig_atomic_t *done,
93294332Sdes    void *ctxt)
9460573Skris{
95294332Sdes	int r;
96294332Sdes	u_char type;
97294332Sdes	u_int32_t seqnr;
98294332Sdes
9960573Skris	for (;;) {
10060573Skris		if (mode == DISPATCH_BLOCK) {
101294332Sdes			r = ssh_packet_read_seqnr(ssh, &type, &seqnr);
102294332Sdes			if (r != 0)
103294332Sdes				return r;
10460573Skris		} else {
105294332Sdes			r = ssh_packet_read_poll_seqnr(ssh, &type, &seqnr);
106294332Sdes			if (r != 0)
107294332Sdes				return r;
10860573Skris			if (type == SSH_MSG_NONE)
109294332Sdes				return 0;
11060573Skris		}
111294332Sdes		if (type > 0 && type < DISPATCH_MAX &&
112294332Sdes		    ssh->dispatch[type] != NULL) {
113294332Sdes			if (ssh->dispatch_skip_packets) {
114294332Sdes				debug2("skipped packet (type %u)", type);
115294332Sdes				ssh->dispatch_skip_packets--;
116294332Sdes				continue;
117294332Sdes			}
118294332Sdes			/* XXX 'ssh' will replace 'ctxt' later */
119294332Sdes			r = (*ssh->dispatch[type])(type, seqnr, ctxt);
120294332Sdes			if (r != 0)
121294332Sdes				return r;
122294332Sdes		} else {
123294332Sdes			r = sshpkt_disconnect(ssh,
124294332Sdes			    "protocol error: rcvd type %d", type);
125294332Sdes			if (r != 0)
126294332Sdes				return r;
127294332Sdes			return SSH_ERR_DISCONNECTED;
128294332Sdes		}
12960573Skris		if (done != NULL && *done)
130294332Sdes			return 0;
13160573Skris	}
13260573Skris}
133294332Sdes
134294332Sdesvoid
135294332Sdesssh_dispatch_run_fatal(struct ssh *ssh, int mode, volatile sig_atomic_t *done,
136294332Sdes    void *ctxt)
137294332Sdes{
138294332Sdes	int r;
139294332Sdes
140294336Sdes	if ((r = ssh_dispatch_run(ssh, mode, done, ctxt)) != 0)
141294336Sdes		sshpkt_fatal(ssh, __func__, r);
142294332Sdes}
143