Пример #1
0
static int
server_input_channel_open(int type, u_int32_t seq, struct ssh *ssh)
{
	Channel *c = NULL;
	char *ctype = 0;
	int r;
	u_int rchan, rmaxpack, rwindow;
	size_t len;

	if ((r = sshpkt_get_cstring(ssh, &ctype, &len)) != 0 ||
	    (r = sshpkt_get_u32(ssh, &rchan)) != 0 ||
	    (r = sshpkt_get_u32(ssh, &rwindow)) != 0 ||
	    (r = sshpkt_get_u32(ssh, &rmaxpack)) != 0)
		goto out;

	debug("server_input_channel_open: ctype %s rchan %d win %d max %d",
	    ctype, rchan, rwindow, rmaxpack);

	if (strcmp(ctype, "session") == 0) {
		c = server_request_session(ssh);
	} else if (strcmp(ctype, "direct-tcpip") == 0) {
		c = server_request_direct_tcpip(ssh);
	} else if (strcmp(ctype, "*****@*****.**") == 0) {
		c = server_request_direct_streamlocal(ssh);
	} else if (strcmp(ctype, "*****@*****.**") == 0) {
		c = server_request_tun(ssh);
	}
	if (c != NULL) {
		debug("server_input_channel_open: confirm %s", ctype);
		c->remote_id = rchan;
		c->remote_window = rwindow;
		c->remote_maxpacket = rmaxpack;
		if (c->type != SSH_CHANNEL_CONNECTING) {
			if ((r = sshpkt_start(ssh,
			    SSH2_MSG_CHANNEL_OPEN_CONFIRMATION)) != 0 ||
			    (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
			    (r = sshpkt_put_u32(ssh, c->self)) != 0 ||
			    (r = sshpkt_put_u32(ssh, c->local_window)) != 0 ||
			    (r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0||
			    (r = sshpkt_send(ssh)) != 0)
				goto out;
		}
	} else {
		debug("server_input_channel_open: failure %s", ctype);
		if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN_FAILURE)) != 0 ||
		    (r = sshpkt_put_u32(ssh, rchan)) != 0 ||
		    (r = sshpkt_put_u32(ssh,
		    SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED)) != 0 ||
		    (!(ssh->compat & SSH_BUG_OPENFAILURE) &&
		    (r = sshpkt_put_cstring(ssh, "open failed")) != 0) ||
		    (!(ssh->compat & SSH_BUG_OPENFAILURE) &&
		    (r = sshpkt_put_cstring(ssh, "")) != 0) ||
		    (r = sshpkt_send(ssh)) != 0)
			goto out;
	}
	r = 0;
 out:
	free(ctype);
	return r;
}
Пример #2
0
static Channel *
server_request_direct_tcpip(struct ssh *ssh)
{
	Channel *c = NULL;
	char *target, *originator;
	u_int target_port, originator_port;
	int r;

	if ((r = sshpkt_get_cstring(ssh, &target, NULL)) != 0 ||
	    (r = sshpkt_get_u32(ssh, &target_port)) != 0 ||
	    (r = sshpkt_get_cstring(ssh, &originator, NULL)) != 0 ||
	    (r = sshpkt_get_u32(ssh, &originator_port)) != 0 ||
	    (r = sshpkt_get_end(ssh)) != 0)
		fatal("%s: %s", __func__, ssh_err(r));

	debug("server_request_direct_tcpip: originator %s port %d, target %s "
	    "port %d", originator, originator_port, target, target_port);

	/* XXX fine grained permissions */
	if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0 &&
	    !no_port_forwarding_flag) {
		c = channel_connect_to_port(ssh, target, target_port,
		    "direct-tcpip", "direct-tcpip");
	} else {
		logit("refused local port forward: "
		    "originator %s port %d, target %s port %d",
		    originator, originator_port, target, target_port);
	}

	free(originator);
	free(target);

	return c;
}
Пример #3
0
static int
input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
{
	struct ssh *ssh = ctxt;
	struct kex *kex = ssh->kex;
	int r;
	u_int min = 0, max = 0, nbits = 0;

	debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
	if ((r = sshpkt_get_u32(ssh, &min)) != 0 ||
	    (r = sshpkt_get_u32(ssh, &nbits)) != 0 ||
	    (r = sshpkt_get_u32(ssh, &max)) != 0 ||
	    (r = sshpkt_get_end(ssh)) != 0)
		goto out;
	kex->nbits = nbits;
	kex->min = min;
	kex->max = max;
	min = MAX(DH_GRP_MIN, min);
	max = MIN(DH_GRP_MAX, max);
	nbits = MAX(DH_GRP_MIN, nbits);
	nbits = MIN(DH_GRP_MAX, nbits);

	if (kex->max < kex->min || kex->nbits < kex->min ||
	    kex->max < kex->nbits) {
		r = SSH_ERR_DH_GEX_OUT_OF_RANGE;
		goto out;
	}

	/* Contact privileged parent */
	kex->dh = PRIVSEP(choose_dh(min, nbits, max));
	if (kex->dh == NULL) {
		sshpkt_disconnect(ssh, "no matching DH grp found");
		r = SSH_ERR_ALLOC_FAIL;
		goto out;
	}
	debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
	if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_GROUP)) != 0 ||
	    (r = sshpkt_put_bignum2(ssh, kex->dh->p)) != 0 ||
	    (r = sshpkt_put_bignum2(ssh, kex->dh->g)) != 0 ||
	    (r = sshpkt_send(ssh)) != 0)
		goto out;

	/* Compute our exchange value in parallel with the client */
	if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
		goto out;

	debug("expecting SSH2_MSG_KEX_DH_GEX_INIT");
	ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_INIT, &input_kex_dh_gex_init);
	r = 0;
 out:
	return r;
}
Пример #4
0
static int
server_input_window_size(int type, u_int32_t seq, struct ssh *ssh)
{
	u_int row, col, xpixel, ypixel;
	int r;

	if ((r = sshpkt_get_u32(ssh, &row)) != 0 ||
	    (r = sshpkt_get_u32(ssh, &col)) != 0 ||
	    (r = sshpkt_get_u32(ssh, &xpixel)) != 0 ||
	    (r = sshpkt_get_u32(ssh, &ypixel)) != 0 ||
	    (r = sshpkt_get_end(ssh)))
		return r;

	debug("Window change received.");
	if (fdin != -1)
		pty_change_window_size(fdin, row, col, xpixel, ypixel);
	return 0;
}
Пример #5
0
u_int
ssh_packet_get_int(struct ssh *ssh)
{
	u_int val;
	int r;

	if ((r = sshpkt_get_u32(ssh, &val)) != 0)
		fatal("%s: %s", __func__, ssh_err(r));
	return val;
}
Пример #6
0
static Channel *
server_request_tun(struct ssh *ssh)
{
	Channel *c = NULL;
	int r, sock;
	u_int tun, mode;

	if ((r = sshpkt_get_u32(ssh, &mode)) != 0 ||
	    (r = sshpkt_get_u32(ssh, &tun)) != 0)
		fatal("%s: %s", __func__, ssh_err(r));
	switch (mode) {
	case SSH_TUNMODE_POINTOPOINT:
	case SSH_TUNMODE_ETHERNET:
		break;
	default:
		ssh_packet_send_debug(ssh, "Unsupported tunnel device mode.");
		return NULL;
	}
	if ((options.permit_tun & mode) == 0) {
		ssh_packet_send_debug(ssh, "Server has rejected tunnel device "
		    "forwarding");
		return NULL;
	}
	if (forced_tun_device >= 0) {
		if (tun != SSH_TUNID_ANY && (u_int)forced_tun_device != tun)
			goto done;
		tun = forced_tun_device;
	}
	sock = tun_open(tun, mode);
	if (sock < 0)
		goto done;
	c = channel_new(ssh, "tun", SSH_CHANNEL_OPEN, sock, sock, -1,
	    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
	c->datagram = 1;

 done:
	if (c == NULL)
		ssh_packet_send_debug(ssh, "Failed to open the tunnel device.");
	return c;
}
Пример #7
0
/* ARGSUSED */
int
kex_input_kexinit(int type, u_int32_t seq, void *ctxt)
{
	struct ssh *ssh = ctxt;
	struct kex *kex = ssh->kex;
	const u_char *ptr;
	u_int i;
	size_t dlen;
	int r;

	debug("SSH2_MSG_KEXINIT received");
	if (kex == NULL)
		return SSH_ERR_INVALID_ARGUMENT;

	ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL);
	ptr = sshpkt_ptr(ssh, &dlen);
	if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0)
		return r;

	/* discard packet */
	for (i = 0; i < KEX_COOKIE_LEN; i++)
		if ((r = sshpkt_get_u8(ssh, NULL)) != 0)
			return r;
	for (i = 0; i < PROPOSAL_MAX; i++)
		if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0)
			return r;
	/*
	 * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported
	 * KEX method has the server move first, but a server might be using
	 * a custom method or one that we otherwise don't support. We should
	 * be prepared to remember first_kex_follows here so we can eat a
	 * packet later.
	 * XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means
	 * for cases where the server *doesn't* go first. I guess we should
	 * ignore it when it is set for these cases, which is what we do now.
	 */
	if ((r = sshpkt_get_u8(ssh, NULL)) != 0 ||	/* first_kex_follows */
	    (r = sshpkt_get_u32(ssh, NULL)) != 0 ||	/* reserved */
	    (r = sshpkt_get_end(ssh)) != 0)
			return r;

	if (!(kex->flags & KEX_INIT_SENT))
		if ((r = kex_send_kexinit(ssh)) != 0)
			return r;
	if ((r = kex_choose_conf(ssh)) != 0)
		return r;

	if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL)
		return (kex->kex[kex->kex_type])(ssh);

	return SSH_ERR_INTERNAL_ERROR;
}
Пример #8
0
/* ARGSUSED */
int
kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh)
{
	Kex *kex = ssh->kex;
	u_char *ptr;
	u_int i;
	size_t dlen;
	int r;

	debug("SSH2_MSG_KEXINIT received");
	if (kex == NULL)
		return SSH_ERR_INVALID_ARGUMENT;

	ptr = sshpkt_ptr(ssh, &dlen);
	if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0)
		return r;

	/* discard packet */
	for (i = 0; i < KEX_COOKIE_LEN; i++)
		if ((r = sshpkt_get_u8(ssh, NULL)) != 0)
			return r;
	for (i = 0; i < PROPOSAL_MAX; i++)
		if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0)
			return r;
	if ((r = sshpkt_get_u8(ssh, NULL)) != 0 ||
	    (r = sshpkt_get_u32(ssh, NULL)) != 0 ||
	    (r = sshpkt_get_end(ssh)) != 0)
			return r;

	if (!(kex->flags & KEX_INIT_SENT))
		if ((r = kex_send_kexinit(ssh)) != 0)
			return r;
	if ((r = kex_choose_conf(ssh)) != 0)
		return r;

	if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX &&
	    kex->kex[kex->kex_type] != NULL)
		return (kex->kex[kex->kex_type])(ssh);

	return SSH_ERR_INTERNAL_ERROR;
}
Пример #9
0
static int
server_input_channel_req(int type, u_int32_t seq, struct ssh *ssh)
{
	Channel *c;
	int r, success = 0;
	u_int id;
	u_char reply;
	char *rtype = NULL;

	if ((r = sshpkt_get_u32(ssh, &id)) != 0 ||
	    (r = sshpkt_get_cstring(ssh, &rtype, NULL)) != 0 ||
	    (r = sshpkt_get_u8(ssh, &reply)) != 0)
		goto out;

	debug("server_input_channel_req: channel %u request %s reply %d",
	    id, rtype, reply);

	if ((c = channel_lookup(id)) == NULL)
		ssh_packet_disconnect(ssh, "server_input_channel_req: "
		    "unknown channel %u", id);
	if (!strcmp(rtype, "*****@*****.**")) {
		if ((r = sshpkt_get_end(ssh)) != 0)
			goto out;
		chan_rcvd_eow(c);
	} else if ((c->type == SSH_CHANNEL_LARVAL ||
	    c->type == SSH_CHANNEL_OPEN) && strcmp(c->ctype, "session") == 0)
		success = session_input_channel_req(c, rtype);
	if (reply && !(c->flags & CHAN_CLOSE_SENT)) {
		if ((r = sshpkt_start(ssh, success ? SSH2_MSG_CHANNEL_SUCCESS :
		    SSH2_MSG_CHANNEL_FAILURE)) != 0 ||
		    (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
		    (r = sshpkt_send(ssh)) != 0)
			goto out;
	}
	r = 0;
 out:
	if (rtype)
		free(rtype);
	return r;
}
Пример #10
0
int
kex_input_ext_info(int type, u_int32_t seq, void *ctxt)
{
	struct ssh *ssh = ctxt;
	struct kex *kex = ssh->kex;
	u_int32_t i, ninfo;
	char *name, *val, *found;
	int r;

	debug("SSH2_MSG_EXT_INFO received");
	ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error);
	if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0)
		return r;
	for (i = 0; i < ninfo; i++) {
		if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0)
			return r;
		if ((r = sshpkt_get_cstring(ssh, &val, NULL)) != 0) {
			free(name);
			return r;
		}
		debug("%s: %s=<%s>", __func__, name, val);
		if (strcmp(name, "server-sig-algs") == 0) {
			found = match_list("rsa-sha2-256", val, NULL);
			if (found) {
				kex->rsa_sha2 = 256;
				free(found);
			}
			found = match_list("rsa-sha2-512", val, NULL);
			if (found) {
				kex->rsa_sha2 = 512;
				free(found);
			}
		}
		free(name);
		free(val);
	}
	return sshpkt_get_end(ssh);
}
Пример #11
0
/*
 * We only support those mechanisms that we know about (ie ones that we know
 * how to check local user kuserok and the like)
 */
static int
userauth_gssapi(struct ssh *ssh)
{
	Authctxt *authctxt = ssh->authctxt;
	gss_OID_desc goid = {0, NULL};
	Gssctxt *ctxt = NULL;
	int r, present;
	u_int mechs;
	OM_uint32 ms;
	size_t len;
	u_char *doid = NULL;

	if ((r = sshpkt_get_u32(ssh, &mechs)) != 0)
		fatal("%s: %s", __func__, ssh_err(r));

	if (mechs == 0) {
		debug("Mechanism negotiation is not supported");
		return (0);
	}

	do {
		mechs--;

		free(doid);

		present = 0;
		if ((r = sshpkt_get_string(ssh, &doid, &len)) != 0)
			fatal("%s: %s", __func__, ssh_err(r));

		if (len > 2 && doid[0] == SSH_GSS_OIDTYPE &&
		    doid[1] == len - 2) {
			goid.elements = doid + 2;
			goid.length   = len - 2;
			ssh_gssapi_test_oid_supported(&ms, &goid, &present);
		} else {
			logit("Badly formed OID received");
		}
	} while (mechs > 0 && !present);

	if (!present) {
		free(doid);
		authctxt->server_caused_failure = 1;
		return (0);
	}

	if (!authctxt->valid || authctxt->user == NULL) {
		debug2("%s: disabled because of invalid user", __func__);
		free(doid);
		return (0);
	}

	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) {
		if (ctxt != NULL)
			ssh_gssapi_delete_ctx(&ctxt);
		free(doid);
		authctxt->server_caused_failure = 1;
		return (0);
	}

	authctxt->methoddata = (void *)ctxt;

	/* Return the OID that we received */
	if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_GSSAPI_RESPONSE)) != 0 ||
	    (r = sshpkt_put_string(ssh, doid, len)) != 0 ||
	    (r = sshpkt_send(ssh)) != 0)
		fatal("%s: %s", __func__, ssh_err(r));

	free(doid);

	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
	authctxt->postponed = 1;

	return (0);
}
Пример #12
0
static int
input_userauth_info_response(int type, u_int32_t seq, struct ssh *ssh)
{
	struct authctxt *authctxt = ssh->authctxt;
	struct kbdintctxt *kbdintctxt;
	int authenticated = 0, res;
	int r;
	u_int i, nresp;
	const char *devicename = NULL;
	char **response = NULL;

	if (authctxt == NULL)
		fatal("input_userauth_info_response: no authctxt");
	kbdintctxt = authctxt->kbdintctxt;
	if (kbdintctxt == NULL || kbdintctxt->ctxt == NULL)
		fatal("input_userauth_info_response: no kbdintctxt");
	if (kbdintctxt->device == NULL)
		fatal("input_userauth_info_response: no device");

	authctxt->postponed = 0;	/* reset */
	if ((r = sshpkt_get_u32(ssh, &nresp)) != 0)
		fatal("%s: %s", __func__, ssh_err(r));
	if (nresp != kbdintctxt->nreq)
		fatal("input_userauth_info_response: wrong number of replies");
	if (nresp > 100)
		fatal("input_userauth_info_response: too many replies");
	if (nresp > 0) {
		response = xcalloc(nresp, sizeof(char *));
		for (i = 0; i < nresp; i++)
			if ((r = sshpkt_get_cstring(ssh, &response[i],
			    NULL)) != 0)
				fatal("%s: %s", __func__, ssh_err(r));
	}
	if ((r = sshpkt_get_end(ssh)) != 0)
		fatal("%s: %s", __func__, ssh_err(r));

	res = kbdintctxt->device->respond(kbdintctxt->ctxt, nresp, response);

	for (i = 0; i < nresp; i++) {
		explicit_bzero(response[i], strlen(response[i]));
		free(response[i]);
	}
	free(response);

	switch (res) {
	case 0:
		/* Success! */
		authenticated = authctxt->valid ? 1 : 0;
		break;
	case 1:
		/* Authentication needs further interaction */
		if (send_userauth_info_request(ssh) == 1)
			authctxt->postponed = 1;
		break;
	default:
		/* Failure! */
		break;
	}
	devicename = kbdintctxt->device->name;
	if (!authctxt->postponed) {
		if (authenticated) {
			auth2_challenge_stop(ssh);
		} else {
			/* start next device */
			/* may set authctxt->postponed */
			auth2_challenge_start(ssh);
		}
	}
	userauth_finish(ssh, authenticated, "keyboard-interactive",
	    devicename);
	return 0;
}
Пример #13
0
static int
server_input_global_request(int type, u_int32_t seq, struct ssh *ssh)
{
	char *rtype = NULL;
	u_char want_reply;
	int r, success = 0, allocated_listen_port = 0;
	struct sshbuf *resp = NULL;

	if ((r = sshpkt_get_cstring(ssh, &rtype, NULL)) != 0 ||
	    (r = sshpkt_get_u8(ssh, &want_reply)) != 0)
		goto out;
	debug("server_input_global_request: rtype %s want_reply %d", rtype, want_reply);

	/* -R style forwarding */
	if (strcmp(rtype, "tcpip-forward") == 0) {
		struct authctxt *authctxt = ssh->authctxt;
		struct Forward fwd;

		if (authctxt->pw == NULL || !authctxt->valid)
			fatal("server_input_global_request: no/invalid user");
		memset(&fwd, 0, sizeof(fwd));
		if ((r = sshpkt_get_cstring(ssh, &fwd.listen_host, NULL)) != 0 ||
		    (r = sshpkt_get_u32(ssh, &fwd.listen_port)) != 0)
			goto out;
		debug("server_input_global_request: tcpip-forward listen %s port %d",
		    fwd.listen_host, fwd.listen_port);

		/* check permissions */
		if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0 ||
		    no_port_forwarding_flag ||
		    (!want_reply && fwd.listen_port == 0) ||
		    (fwd.listen_port != 0 && fwd.listen_port < IPPORT_RESERVED &&
		    authctxt->pw->pw_uid != 0)) {
			success = 0;
			ssh_packet_send_debug(ssh,
			    "Server has disabled port forwarding.");
		} else {
			/* Start listening on the port */
			success = channel_setup_remote_fwd_listener(ssh, &fwd,
			    &allocated_listen_port, &options.fwd_opts);
		}
		free(fwd.listen_host);
		if ((resp = sshbuf_new()) == NULL)
			fatal("%s: sshbuf_new", __func__);
		if (allocated_listen_port != 0 &&
		    (r = sshbuf_put_u32(resp, allocated_listen_port)) != 0)
			fatal("%s: sshbuf_put_u32: %s", __func__, ssh_err(r));
	} else if (strcmp(rtype, "cancel-tcpip-forward") == 0) {
		struct Forward fwd;

		memset(&fwd, 0, sizeof(fwd));
		if ((r = sshpkt_get_cstring(ssh, &fwd.listen_host, NULL)) != 0 ||
		    (r = sshpkt_get_u32(ssh, &fwd.listen_port)) != 0)
			goto out;
		debug("%s: cancel-tcpip-forward addr %s port %d", __func__,
		    fwd.listen_host, fwd.listen_port);

		success = channel_cancel_rport_listener(&fwd);
		free(fwd.listen_host);
	} else if (strcmp(rtype, "*****@*****.**") == 0) {
		struct Forward fwd;

		memset(&fwd, 0, sizeof(fwd));
		if ((r = sshpkt_get_cstring(ssh, &fwd.listen_path, NULL)) != 0)
			goto out;
		debug("server_input_global_request: streamlocal-forward listen path %s",
		    fwd.listen_path);

		/* check permissions */
		if ((options.allow_streamlocal_forwarding & FORWARD_REMOTE) == 0
		    || no_port_forwarding_flag) {
			success = 0;
			ssh_packet_send_debug(ssh, "Server has disabled port forwarding.");
		} else {
			/* Start listening on the socket */
			success = channel_setup_remote_fwd_listener(ssh,
			    &fwd, NULL, &options.fwd_opts);
		}
		free(fwd.listen_path);
	} else if (strcmp(rtype, "*****@*****.**") == 0) {
		struct Forward fwd;

		memset(&fwd, 0, sizeof(fwd));
		if ((r = sshpkt_get_cstring(ssh, &fwd.listen_path, NULL)) != 0)
			goto out;
		debug("%s: cancel-streamlocal-forward path %s", __func__,
		    fwd.listen_path);

		success = channel_cancel_rport_listener(&fwd);
		free(fwd.listen_path);
	} else if (strcmp(rtype, "*****@*****.**") == 0) {
		no_more_sessions = 1;
		success = 1;
	} else if (strcmp(rtype, "*****@*****.**") == 0) {
		success = server_input_hostkeys_prove(&resp);
	}
	if (want_reply) {
		if ((r = sshpkt_start(ssh, success ?
		    SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE)) != 0 ||
		    (success && resp != NULL &&
		    (r = sshpkt_put(ssh, sshbuf_ptr(resp), sshbuf_len(resp)))
		    != 0) ||
		    (r = sshpkt_send(ssh)) != 0) 
			goto out;
		ssh_packet_write_wait(ssh);
	}
	r = 0;
 out:
	free(rtype);
	sshbuf_free(resp);
	return r;
}
Пример #14
0
static int
input_kex_dh_gex_request(int type, u_int32_t seq, struct ssh *ssh)
{
	Kex *kex = ssh->kex;
	int r, min = -1, max = -1, nbits = -1;

	switch (type) {
	case SSH2_MSG_KEX_DH_GEX_REQUEST:
		debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
		if ((r = sshpkt_get_u32(ssh, &min)) != 0 ||
		    (r = sshpkt_get_u32(ssh, &nbits)) != 0 ||
		    (r = sshpkt_get_u32(ssh, &max)) != 0 ||
		    (r = sshpkt_get_end(ssh)) != 0)
			goto out;
		kex->nbits = nbits;
		kex->min = min;
		kex->max = max;
		min = MAX(DH_GRP_MIN, min);
		max = MIN(DH_GRP_MAX, max);
		nbits = MAX(DH_GRP_MIN, nbits);
		nbits = MIN(DH_GRP_MAX, nbits);
		break;
	case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:
		debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received");
		if ((r = sshpkt_get_u32(ssh, &nbits)) != 0 ||
		    (r = sshpkt_get_end(ssh)) != 0)
			goto out;
		kex->nbits = nbits;
		/* unused for old GEX */
		kex->min = min = DH_GRP_MIN;
		kex->max = max = DH_GRP_MAX;
		break;
	default:
		r = SSH_ERR_INVALID_ARGUMENT;
		goto out;
	}

	if (kex->max < kex->min || kex->nbits < kex->min ||
	    kex->max < kex->nbits) {
		r = SSH_ERR_DH_GEX_OUT_OF_RANGE;
		goto out;
	}

	/* Contact privileged parent */
	kex->dh = PRIVSEP(choose_dh(min, nbits, max));
	if (kex->dh == NULL) {
		sshpkt_disconnect(ssh, "no matching DH grp found");
		r = SSH_ERR_ALLOC_FAIL;
		goto out;
	}
	debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
	if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_GROUP)) != 0 ||
	    (r = sshpkt_put_bignum2(ssh, kex->dh->p)) != 0 ||
	    (r = sshpkt_put_bignum2(ssh, kex->dh->g)) != 0 ||
	    (r = sshpkt_send(ssh)) != 0)
		goto out;

	/* Compute our exchange value in parallel with the client */
	if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
		goto out;

	/* old KEX does not use min/max in kexgex_hash() */
	if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD)
		kex->min = kex->max = -1;

	debug("expecting SSH2_MSG_KEX_DH_GEX_INIT");
	ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_INIT, &input_kex_dh_gex_init);
	r = 0;
 out:
	return r;
}