mirror of
https://github.com/PowerShell/openssh-portable.git
synced 2025-07-28 16:24:39 +02:00
- More large OpenBSD CVS updates:
- [auth.c auth.h servconf.c servconf.h serverloop.c session.c] [session.h ssh.h sshd.c README.openssh2] ssh2 server side, see README.openssh2; enable with 'sshd -2' - [channels.c] no adjust after close - [sshd.c compat.c ] interop w/ latest ssh.com windows client.
This commit is contained in:
parent
11e37f638d
commit
efb4afe026
10
ChangeLog
10
ChangeLog
@ -2,7 +2,15 @@
|
|||||||
- Avoid some compiler warnings in fake-get*.c
|
- Avoid some compiler warnings in fake-get*.c
|
||||||
- Add IPTOS macros for systems which lack them
|
- Add IPTOS macros for systems which lack them
|
||||||
- Only set define entropy collection macros if they are found
|
- Only set define entropy collection macros if they are found
|
||||||
|
- More large OpenBSD CVS updates:
|
||||||
|
- [auth.c auth.h servconf.c servconf.h serverloop.c session.c]
|
||||||
|
[session.h ssh.h sshd.c README.openssh2]
|
||||||
|
ssh2 server side, see README.openssh2; enable with 'sshd -2'
|
||||||
|
- [channels.c]
|
||||||
|
no adjust after close
|
||||||
|
- [sshd.c compat.c ]
|
||||||
|
interop w/ latest ssh.com windows client.
|
||||||
|
|
||||||
20000406
|
20000406
|
||||||
- OpenBSD CVS update:
|
- OpenBSD CVS update:
|
||||||
- [channels.c]
|
- [channels.c]
|
||||||
|
36
README.openssh2
Normal file
36
README.openssh2
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
$Id: README.openssh2,v 1.2 2000/04/06 21:28:22 markus Exp $
|
||||||
|
|
||||||
|
works:
|
||||||
|
secsh-transport: works w/o rekey
|
||||||
|
proposal exchange, i.e. different enc/mac/comp per direction
|
||||||
|
encryption: blowfish-cbc, 3des-cbc, arcfour, cast128-cbc
|
||||||
|
mac: hmac-md5, hmac-sha1, (hmac-ripemd160)
|
||||||
|
compression: zlib, none
|
||||||
|
secsh-userauth: passwd only
|
||||||
|
secsh-connection: pty+shell or command, flow control works (window adjust)
|
||||||
|
tcp-forwarding: -L works
|
||||||
|
dss: verification works,
|
||||||
|
key database in ~/.ssh/known_hosts with bits == 0 hack
|
||||||
|
dss: signature works, keygen w/ openssl:
|
||||||
|
$ umask 077
|
||||||
|
$ openssl dsaparam 1024 -out dsa1024.pem
|
||||||
|
$ openssl gendsa -out /etc/ssh_dsa_key dsa1024.pem -rand /dev/arandom
|
||||||
|
start sshd with '-2' flag
|
||||||
|
client interops w/ sshd2, lshd
|
||||||
|
server interops w/ ssh2, lsh, ssh.com's Windows client, SecureCRT
|
||||||
|
server supports multiple concurrent sessions (e.g. with SSH.com Windows client)
|
||||||
|
todo:
|
||||||
|
re-keying
|
||||||
|
secsh-connection features:
|
||||||
|
tcp-forwarding, agent-fwd, x11-fwd
|
||||||
|
auth other than passwd:
|
||||||
|
pubkey, keyboard-interactive
|
||||||
|
config
|
||||||
|
server-auth w/ old host-keys
|
||||||
|
cleanup
|
||||||
|
advanced key storage?
|
||||||
|
keynote
|
||||||
|
sftp
|
||||||
|
|
||||||
|
-markus
|
||||||
|
$Date: 2000/04/06 21:28:22 $
|
188
auth.c
188
auth.c
@ -1,10 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
|
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$OpenBSD: auth.c,v 1.1 2000/03/28 21:15:45 markus Exp $");
|
RCSID("$OpenBSD: auth.c,v 1.2 2000/04/06 08:55:22 markus Exp $");
|
||||||
|
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "rsa.h"
|
#include "rsa.h"
|
||||||
@ -15,12 +16,17 @@ RCSID("$OpenBSD: auth.c,v 1.1 2000/03/28 21:15:45 markus Exp $");
|
|||||||
#include "cipher.h"
|
#include "cipher.h"
|
||||||
#include "mpaux.h"
|
#include "mpaux.h"
|
||||||
#include "servconf.h"
|
#include "servconf.h"
|
||||||
|
#include "compat.h"
|
||||||
#include "channels.h"
|
#include "channels.h"
|
||||||
#include "match.h"
|
#include "match.h"
|
||||||
|
|
||||||
|
#include "bufaux.h"
|
||||||
|
#include "ssh2.h"
|
||||||
|
#include "auth.h"
|
||||||
#include "session.h"
|
#include "session.h"
|
||||||
#include "dispatch.h"
|
#include "dispatch.h"
|
||||||
|
|
||||||
|
|
||||||
/* import */
|
/* import */
|
||||||
extern ServerOptions options;
|
extern ServerOptions options;
|
||||||
extern char *forced_command;
|
extern char *forced_command;
|
||||||
@ -604,3 +610,183 @@ do_authentication()
|
|||||||
/* Perform session preparation. */
|
/* Perform session preparation. */
|
||||||
do_authenticated(pw);
|
do_authenticated(pw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void input_service_request(int type, int plen);
|
||||||
|
void input_userauth_request(int type, int plen);
|
||||||
|
void ssh2_pty_cleanup(void);
|
||||||
|
|
||||||
|
typedef struct Authctxt Authctxt;
|
||||||
|
struct Authctxt {
|
||||||
|
char *user;
|
||||||
|
char *service;
|
||||||
|
struct passwd pw;
|
||||||
|
int valid;
|
||||||
|
};
|
||||||
|
static Authctxt *authctxt = NULL;
|
||||||
|
static int userauth_success = 0;
|
||||||
|
|
||||||
|
struct passwd*
|
||||||
|
auth_get_user(void)
|
||||||
|
{
|
||||||
|
return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
|
||||||
|
}
|
||||||
|
struct passwd*
|
||||||
|
auth_set_user(char *u, char *s)
|
||||||
|
{
|
||||||
|
struct passwd *pw, *copy;
|
||||||
|
|
||||||
|
if (authctxt == NULL) {
|
||||||
|
authctxt = xmalloc(sizeof(*authctxt));
|
||||||
|
authctxt->valid = 0;
|
||||||
|
authctxt->user = xstrdup(u);
|
||||||
|
authctxt->service = xstrdup(s);
|
||||||
|
setproctitle("%s", u);
|
||||||
|
pw = getpwnam(u);
|
||||||
|
if (!pw || !allowed_user(pw)) {
|
||||||
|
log("auth_set_user: bad user %s", u);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#ifdef USE_PAM
|
||||||
|
start_pam(pw);
|
||||||
|
#endif
|
||||||
|
copy = &authctxt->pw;
|
||||||
|
memset(copy, 0, sizeof(*copy));
|
||||||
|
copy->pw_name = xstrdup(pw->pw_name);
|
||||||
|
copy->pw_passwd = xstrdup(pw->pw_passwd);
|
||||||
|
copy->pw_uid = pw->pw_uid;
|
||||||
|
copy->pw_gid = pw->pw_gid;
|
||||||
|
copy->pw_dir = xstrdup(pw->pw_dir);
|
||||||
|
copy->pw_shell = xstrdup(pw->pw_shell);
|
||||||
|
authctxt->valid = 1;
|
||||||
|
} else {
|
||||||
|
if (strcmp(u, authctxt->user) != 0 ||
|
||||||
|
strcmp(s, authctxt->service) != 0) {
|
||||||
|
log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
|
||||||
|
u, s, authctxt->user, authctxt->service);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return auth_get_user();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
protocol_error(int type, int plen)
|
||||||
|
{
|
||||||
|
log("auth: protocol error: type %d plen %d", type, plen);
|
||||||
|
packet_start(SSH2_MSG_UNIMPLEMENTED);
|
||||||
|
packet_put_int(0);
|
||||||
|
packet_send();
|
||||||
|
packet_write_wait();
|
||||||
|
}
|
||||||
|
void
|
||||||
|
input_service_request(int type, int plen)
|
||||||
|
{
|
||||||
|
unsigned int len;
|
||||||
|
int accept = 0;
|
||||||
|
char *service = packet_get_string(&len);
|
||||||
|
|
||||||
|
if (strcmp(service, "ssh-userauth") == 0) {
|
||||||
|
if (!userauth_success) {
|
||||||
|
accept = 1;
|
||||||
|
/* now we can handle user-auth requests */
|
||||||
|
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* XXX all other service requests are denied */
|
||||||
|
|
||||||
|
if (accept) {
|
||||||
|
packet_start(SSH2_MSG_SERVICE_ACCEPT);
|
||||||
|
packet_put_cstring(service);
|
||||||
|
packet_send();
|
||||||
|
packet_write_wait();
|
||||||
|
} else {
|
||||||
|
debug("bad service request %s", service);
|
||||||
|
packet_disconnect("bad service request %s", service);
|
||||||
|
}
|
||||||
|
xfree(service);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
input_userauth_request(int type, int plen)
|
||||||
|
{
|
||||||
|
static int try = 0;
|
||||||
|
unsigned int len;
|
||||||
|
int c, authenticated = 0;
|
||||||
|
char *user, *service, *method;
|
||||||
|
struct passwd *pw;
|
||||||
|
|
||||||
|
if (++try == AUTH_FAIL_MAX)
|
||||||
|
packet_disconnect("too many failed userauth_requests");
|
||||||
|
|
||||||
|
user = packet_get_string(&len);
|
||||||
|
service = packet_get_string(&len);
|
||||||
|
method = packet_get_string(&len);
|
||||||
|
debug("userauth-request for user %s service %s method %s", user, service, method);
|
||||||
|
|
||||||
|
/* XXX we only allow the ssh-connection service */
|
||||||
|
pw = auth_set_user(user, service);
|
||||||
|
if (pw && strcmp(service, "ssh-connection")==0) {
|
||||||
|
if (strcmp(method, "none") == 0 && try == 1) {
|
||||||
|
#ifdef USE_PAM
|
||||||
|
/* Do PAM auth with password */
|
||||||
|
authenticated = auth_pam_password(pw, "");
|
||||||
|
#else /* USE_PAM */
|
||||||
|
/* Try authentication with the password. */
|
||||||
|
authenticated = auth_password(pw, "");
|
||||||
|
#endif /* USE_PAM */
|
||||||
|
} else if (strcmp(method, "password") == 0) {
|
||||||
|
char *password;
|
||||||
|
c = packet_get_char();
|
||||||
|
if (c)
|
||||||
|
debug("password change not supported");
|
||||||
|
password = packet_get_string(&len);
|
||||||
|
#ifdef USE_PAM
|
||||||
|
/* Do PAM auth with password */
|
||||||
|
authenticated = auth_pam_password(pw, password);
|
||||||
|
#else /* USE_PAM */
|
||||||
|
/* Try authentication with the password. */
|
||||||
|
authenticated = auth_password(pw, password);
|
||||||
|
#endif /* USE_PAM */
|
||||||
|
memset(password, 0, len);
|
||||||
|
xfree(password);
|
||||||
|
} else if (strcmp(method, "publickey") == 0) {
|
||||||
|
/* XXX TODO */
|
||||||
|
char *pkalg;
|
||||||
|
char *pkblob;
|
||||||
|
c = packet_get_char();
|
||||||
|
pkalg = packet_get_string(&len);
|
||||||
|
pkblob = packet_get_string(&len);
|
||||||
|
xfree(pkalg);
|
||||||
|
xfree(pkblob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* XXX check if other auth methods are needed */
|
||||||
|
if (authenticated) {
|
||||||
|
/* turn off userauth */
|
||||||
|
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
|
||||||
|
/* success! */
|
||||||
|
packet_start(SSH2_MSG_USERAUTH_SUCCESS);
|
||||||
|
packet_send();
|
||||||
|
packet_write_wait();
|
||||||
|
log("userauth success for %s", user);
|
||||||
|
/* now we can break out */
|
||||||
|
userauth_success = 1;
|
||||||
|
} else {
|
||||||
|
packet_start(SSH2_MSG_USERAUTH_FAILURE);
|
||||||
|
packet_put_cstring("password");
|
||||||
|
packet_put_char(0); /* partial success */
|
||||||
|
packet_send();
|
||||||
|
packet_write_wait();
|
||||||
|
}
|
||||||
|
xfree(service);
|
||||||
|
xfree(user);
|
||||||
|
xfree(method);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
do_authentication2()
|
||||||
|
{
|
||||||
|
dispatch_init(&protocol_error);
|
||||||
|
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
|
||||||
|
dispatch_run(DISPATCH_BLOCK, &userauth_success);
|
||||||
|
do_authenticated2();
|
||||||
|
}
|
||||||
|
4
auth.h
4
auth.h
@ -2,5 +2,9 @@
|
|||||||
#define AUTH_H
|
#define AUTH_H
|
||||||
|
|
||||||
void do_authentication(void);
|
void do_authentication(void);
|
||||||
|
void do_authentication2(void);
|
||||||
|
|
||||||
|
struct passwd *
|
||||||
|
auth_get_user(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: channels.c,v 1.22 2000/04/06 02:32:38 damien Exp $");
|
RCSID("$Id: channels.c,v 1.23 2000/04/12 08:45:06 damien Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
@ -674,7 +674,7 @@ channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset)
|
|||||||
int
|
int
|
||||||
channel_check_window(Channel *c, fd_set * readset, fd_set * writeset)
|
channel_check_window(Channel *c, fd_set * readset, fd_set * writeset)
|
||||||
{
|
{
|
||||||
if (!(c->flags & CHAN_CLOSE_SENT) &&
|
if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) &&
|
||||||
c->local_window < c->local_window_max/2 &&
|
c->local_window < c->local_window_max/2 &&
|
||||||
c->local_consumed > 0) {
|
c->local_consumed > 0) {
|
||||||
packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
|
packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
|
||||||
@ -837,7 +837,8 @@ channel_output_poll()
|
|||||||
c->istate != CHAN_INPUT_WAIT_DRAIN)
|
c->istate != CHAN_INPUT_WAIT_DRAIN)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (compat20 && (c->flags & CHAN_CLOSE_SENT)) {
|
if (compat20 &&
|
||||||
|
(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) {
|
||||||
debug("channel: %d: no data after CLOSE", c->self);
|
debug("channel: %d: no data after CLOSE", c->self);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
6
compat.c
6
compat.c
@ -28,7 +28,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: compat.c,v 1.5 2000/04/06 02:32:39 damien Exp $");
|
RCSID("$Id: compat.c,v 1.6 2000/04/12 08:45:06 damien Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
@ -58,9 +58,7 @@ compat_datafellows(const char *version)
|
|||||||
size_t len;
|
size_t len;
|
||||||
static const char *check[] = {
|
static const char *check[] = {
|
||||||
"2.0.1",
|
"2.0.1",
|
||||||
"2.1.0.beta.9",
|
"2.1.0",
|
||||||
"2.1.0.pre.3",
|
|
||||||
"2.1.0.public.beta.1",
|
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
for (i = 0; check[i]; i++) {
|
for (i = 0; check[i]; i++) {
|
||||||
|
12
servconf.c
12
servconf.c
@ -12,7 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: servconf.c,v 1.9 2000/03/09 10:27:51 damien Exp $");
|
RCSID("$Id: servconf.c,v 1.10 2000/04/12 08:45:06 damien Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "servconf.h"
|
#include "servconf.h"
|
||||||
@ -31,6 +31,7 @@ initialize_server_options(ServerOptions *options)
|
|||||||
options->ports_from_cmdline = 0;
|
options->ports_from_cmdline = 0;
|
||||||
options->listen_addrs = NULL;
|
options->listen_addrs = NULL;
|
||||||
options->host_key_file = NULL;
|
options->host_key_file = NULL;
|
||||||
|
options->dsa_key_file = NULL;
|
||||||
options->server_key_bits = -1;
|
options->server_key_bits = -1;
|
||||||
options->login_grace_time = -1;
|
options->login_grace_time = -1;
|
||||||
options->key_regeneration_time = -1;
|
options->key_regeneration_time = -1;
|
||||||
@ -78,6 +79,8 @@ fill_default_server_options(ServerOptions *options)
|
|||||||
add_listen_addr(options, NULL);
|
add_listen_addr(options, NULL);
|
||||||
if (options->host_key_file == NULL)
|
if (options->host_key_file == NULL)
|
||||||
options->host_key_file = HOST_KEY_FILE;
|
options->host_key_file = HOST_KEY_FILE;
|
||||||
|
if (options->dsa_key_file == NULL)
|
||||||
|
options->dsa_key_file = DSA_KEY_FILE;
|
||||||
if (options->server_key_bits == -1)
|
if (options->server_key_bits == -1)
|
||||||
options->server_key_bits = 768;
|
options->server_key_bits = 768;
|
||||||
if (options->login_grace_time == -1)
|
if (options->login_grace_time == -1)
|
||||||
@ -159,7 +162,7 @@ typedef enum {
|
|||||||
sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset,
|
sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset,
|
||||||
sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
|
sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
|
||||||
sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
|
sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
|
||||||
sIgnoreUserKnownHosts
|
sIgnoreUserKnownHosts, sDSAKeyFile
|
||||||
} ServerOpCodes;
|
} ServerOpCodes;
|
||||||
|
|
||||||
/* Textual representation of the tokens. */
|
/* Textual representation of the tokens. */
|
||||||
@ -169,6 +172,7 @@ static struct {
|
|||||||
} keywords[] = {
|
} keywords[] = {
|
||||||
{ "port", sPort },
|
{ "port", sPort },
|
||||||
{ "hostkey", sHostKeyFile },
|
{ "hostkey", sHostKeyFile },
|
||||||
|
{ "dsakey", sDSAKeyFile },
|
||||||
{ "serverkeybits", sServerKeyBits },
|
{ "serverkeybits", sServerKeyBits },
|
||||||
{ "logingracetime", sLoginGraceTime },
|
{ "logingracetime", sLoginGraceTime },
|
||||||
{ "keyregenerationinterval", sKeyRegenerationTime },
|
{ "keyregenerationinterval", sKeyRegenerationTime },
|
||||||
@ -338,7 +342,9 @@ parse_int:
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case sHostKeyFile:
|
case sHostKeyFile:
|
||||||
charptr = &options->host_key_file;
|
case sDSAKeyFile:
|
||||||
|
charptr = (opcode == sHostKeyFile ) ?
|
||||||
|
&options->host_key_file : &options->dsa_key_file;
|
||||||
cp = strtok(NULL, WHITESPACE);
|
cp = strtok(NULL, WHITESPACE);
|
||||||
if (!cp) {
|
if (!cp) {
|
||||||
fprintf(stderr, "%s line %d: missing file name.\n",
|
fprintf(stderr, "%s line %d: missing file name.\n",
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* RCSID("$Id: servconf.h,v 1.6 2000/01/14 04:45:51 damien Exp $"); */
|
/* RCSID("$Id: servconf.h,v 1.7 2000/04/12 08:45:07 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef SERVCONF_H
|
#ifndef SERVCONF_H
|
||||||
#define SERVCONF_H
|
#define SERVCONF_H
|
||||||
@ -32,6 +32,7 @@ typedef struct {
|
|||||||
char *listen_addr; /* Address on which the server listens. */
|
char *listen_addr; /* Address on which the server listens. */
|
||||||
struct addrinfo *listen_addrs; /* Addresses on which the server listens. */
|
struct addrinfo *listen_addrs; /* Addresses on which the server listens. */
|
||||||
char *host_key_file; /* File containing host key. */
|
char *host_key_file; /* File containing host key. */
|
||||||
|
char *dsa_key_file; /* File containing dsa host key. */
|
||||||
int server_key_bits;/* Size of the server key. */
|
int server_key_bits;/* Size of the server key. */
|
||||||
int login_grace_time; /* Disconnect if no auth in this time
|
int login_grace_time; /* Disconnect if no auth in this time
|
||||||
* (sec). */
|
* (sec). */
|
||||||
|
192
serverloop.c
192
serverloop.c
@ -5,6 +5,10 @@
|
|||||||
* Created: Sun Sep 10 00:30:37 1995 ylo
|
* Created: Sun Sep 10 00:30:37 1995 ylo
|
||||||
* Server main loop for handling the interactive session.
|
* Server main loop for handling the interactive session.
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
|
* SSH2 support by Markus Friedl.
|
||||||
|
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
@ -16,6 +20,8 @@
|
|||||||
#include "channels.h"
|
#include "channels.h"
|
||||||
|
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
|
#include "ssh2.h"
|
||||||
|
#include "session.h"
|
||||||
#include "dispatch.h"
|
#include "dispatch.h"
|
||||||
|
|
||||||
static Buffer stdin_buffer; /* Buffer for stdin data. */
|
static Buffer stdin_buffer; /* Buffer for stdin data. */
|
||||||
@ -72,6 +78,15 @@ sigchld_handler(int sig)
|
|||||||
signal(SIGCHLD, sigchld_handler);
|
signal(SIGCHLD, sigchld_handler);
|
||||||
errno = save_errno;
|
errno = save_errno;
|
||||||
}
|
}
|
||||||
|
void
|
||||||
|
sigchld_handler2(int sig)
|
||||||
|
{
|
||||||
|
int save_errno = errno;
|
||||||
|
debug("Received SIGCHLD.");
|
||||||
|
child_terminated = 1;
|
||||||
|
signal(SIGCHLD, sigchld_handler2);
|
||||||
|
errno = save_errno;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make packets from buffered stderr data, and buffer it for sending
|
* Make packets from buffered stderr data, and buffer it for sending
|
||||||
@ -154,15 +169,21 @@ retry_select:
|
|||||||
* Read packets from the client unless we have too much buffered
|
* Read packets from the client unless we have too much buffered
|
||||||
* stdin or channel data.
|
* stdin or channel data.
|
||||||
*/
|
*/
|
||||||
if (buffer_len(&stdin_buffer) < 4096 &&
|
if (compat20) {
|
||||||
channel_not_very_much_buffered_data())
|
// wrong: bad conditionXXX
|
||||||
FD_SET(connection_in, readset);
|
if (channel_not_very_much_buffered_data())
|
||||||
|
FD_SET(connection_in, readset);
|
||||||
|
} else {
|
||||||
|
if (buffer_len(&stdin_buffer) < 4096 &&
|
||||||
|
channel_not_very_much_buffered_data())
|
||||||
|
FD_SET(connection_in, readset);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there is not too much data already buffered going to the
|
* If there is not too much data already buffered going to the
|
||||||
* client, try to get some more data from the program.
|
* client, try to get some more data from the program.
|
||||||
*/
|
*/
|
||||||
if (packet_not_very_much_data_to_write()) {
|
if (!compat20 && packet_not_very_much_data_to_write()) {
|
||||||
if (!fdout_eof)
|
if (!fdout_eof)
|
||||||
FD_SET(fdout, readset);
|
FD_SET(fdout, readset);
|
||||||
if (!fderr_eof)
|
if (!fderr_eof)
|
||||||
@ -182,7 +203,7 @@ retry_select:
|
|||||||
|
|
||||||
/* If we have buffered data, try to write some of that data to the
|
/* If we have buffered data, try to write some of that data to the
|
||||||
program. */
|
program. */
|
||||||
if (fdin != -1 && buffer_len(&stdin_buffer) > 0)
|
if (!compat20 && fdin != -1 && buffer_len(&stdin_buffer) > 0)
|
||||||
FD_SET(fdin, writeset);
|
FD_SET(fdin, writeset);
|
||||||
|
|
||||||
/* Update the maximum descriptor number if appropriate. */
|
/* Update the maximum descriptor number if appropriate. */
|
||||||
@ -204,6 +225,8 @@ retry_select:
|
|||||||
tv.tv_usec = 1000 * (max_time_milliseconds % 1000);
|
tv.tv_usec = 1000 * (max_time_milliseconds % 1000);
|
||||||
tvp = &tv;
|
tvp = &tv;
|
||||||
}
|
}
|
||||||
|
if (tvp!=NULL)
|
||||||
|
debug("tvp!=NULL kid %d mili %d", child_terminated, max_time_milliseconds);
|
||||||
|
|
||||||
/* Wait for something to happen, or the timeout to expire. */
|
/* Wait for something to happen, or the timeout to expire. */
|
||||||
ret = select(max_fd + 1, readset, writeset, NULL, tvp);
|
ret = select(max_fd + 1, readset, writeset, NULL, tvp);
|
||||||
@ -250,6 +273,9 @@ process_input(fd_set * readset)
|
|||||||
/* Buffer any received data. */
|
/* Buffer any received data. */
|
||||||
packet_process_incoming(buf, len);
|
packet_process_incoming(buf, len);
|
||||||
}
|
}
|
||||||
|
if (compat20)
|
||||||
|
return;
|
||||||
|
|
||||||
/* Read and buffer any available stdout data from the program. */
|
/* Read and buffer any available stdout data from the program. */
|
||||||
if (!fdout_eof && FD_ISSET(fdout, readset)) {
|
if (!fdout_eof && FD_ISSET(fdout, readset)) {
|
||||||
len = read(fdout, buf, sizeof(buf));
|
len = read(fdout, buf, sizeof(buf));
|
||||||
@ -279,7 +305,7 @@ process_output(fd_set * writeset)
|
|||||||
int len;
|
int len;
|
||||||
|
|
||||||
/* Write buffered data to program stdin. */
|
/* Write buffered data to program stdin. */
|
||||||
if (fdin != -1 && FD_ISSET(fdin, writeset)) {
|
if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) {
|
||||||
len = write(fdin, buffer_ptr(&stdin_buffer),
|
len = write(fdin, buffer_ptr(&stdin_buffer),
|
||||||
buffer_len(&stdin_buffer));
|
buffer_len(&stdin_buffer));
|
||||||
if (len <= 0) {
|
if (len <= 0) {
|
||||||
@ -578,6 +604,51 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
|
|||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
server_loop2(void)
|
||||||
|
{
|
||||||
|
fd_set readset, writeset;
|
||||||
|
int had_channel = 0;
|
||||||
|
int status;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
debug("Entering interactive session for SSH2.");
|
||||||
|
|
||||||
|
signal(SIGCHLD, sigchld_handler2);
|
||||||
|
child_terminated = 0;
|
||||||
|
connection_in = packet_get_connection_in();
|
||||||
|
connection_out = packet_get_connection_out();
|
||||||
|
max_fd = connection_in;
|
||||||
|
if (connection_out > max_fd)
|
||||||
|
max_fd = connection_out;
|
||||||
|
server_init_dispatch();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
process_buffered_input_packets();
|
||||||
|
if (!had_channel && channel_still_open())
|
||||||
|
had_channel = 1;
|
||||||
|
if (had_channel && !channel_still_open()) {
|
||||||
|
debug("!channel_still_open.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (packet_not_very_much_data_to_write())
|
||||||
|
channel_output_poll();
|
||||||
|
wait_until_can_do_something(&readset, &writeset, 0);
|
||||||
|
if (child_terminated) {
|
||||||
|
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
|
||||||
|
session_close_by_pid(pid, status);
|
||||||
|
child_terminated = 0;
|
||||||
|
}
|
||||||
|
channel_after_select(&readset, &writeset);
|
||||||
|
process_input(&readset);
|
||||||
|
process_output(&writeset);
|
||||||
|
}
|
||||||
|
signal(SIGCHLD, SIG_DFL);
|
||||||
|
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
|
||||||
|
session_close_by_pid(pid, status);
|
||||||
|
channel_stop_listening();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
server_input_stdin_data(int type, int plen)
|
server_input_stdin_data(int type, int plen)
|
||||||
{
|
{
|
||||||
@ -622,6 +693,111 @@ server_input_window_size(int type, int plen)
|
|||||||
pty_change_window_size(fdin, row, col, xpixel, ypixel);
|
pty_change_window_size(fdin, row, col, xpixel, ypixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
input_direct_tcpip(void)
|
||||||
|
{
|
||||||
|
int sock;
|
||||||
|
char *host, *originator;
|
||||||
|
int host_port, originator_port;
|
||||||
|
|
||||||
|
host = packet_get_string(NULL);
|
||||||
|
host_port = packet_get_int();
|
||||||
|
originator = packet_get_string(NULL);
|
||||||
|
originator_port = packet_get_int();
|
||||||
|
/* XXX check permission */
|
||||||
|
sock = channel_connect_to(host, host_port);
|
||||||
|
xfree(host);
|
||||||
|
xfree(originator);
|
||||||
|
if (sock < 0)
|
||||||
|
return -1;
|
||||||
|
return channel_new("direct-tcpip", SSH_CHANNEL_OPEN,
|
||||||
|
sock, sock, -1, 4*1024, 32*1024, 0, xstrdup("direct-tcpip"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
server_input_channel_open(int type, int plen)
|
||||||
|
{
|
||||||
|
Channel *c = NULL;
|
||||||
|
char *ctype;
|
||||||
|
int id;
|
||||||
|
unsigned int len;
|
||||||
|
int rchan;
|
||||||
|
int rmaxpack;
|
||||||
|
int rwindow;
|
||||||
|
|
||||||
|
ctype = packet_get_string(&len);
|
||||||
|
rchan = packet_get_int();
|
||||||
|
rwindow = packet_get_int();
|
||||||
|
rmaxpack = packet_get_int();
|
||||||
|
|
||||||
|
log("channel_input_open: ctype %s rchan %d win %d max %d",
|
||||||
|
ctype, rchan, rwindow, rmaxpack);
|
||||||
|
|
||||||
|
if (strcmp(ctype, "session") == 0) {
|
||||||
|
debug("open session");
|
||||||
|
/*
|
||||||
|
* A server session has no fd to read or write
|
||||||
|
* until a CHANNEL_REQUEST for a shell is made,
|
||||||
|
* so we set the type to SSH_CHANNEL_LARVAL.
|
||||||
|
* Additionally, a callback for handling all
|
||||||
|
* CHANNEL_REQUEST messages is registered.
|
||||||
|
*/
|
||||||
|
id = channel_new(ctype, SSH_CHANNEL_LARVAL,
|
||||||
|
-1, -1, -1, 0, 32*1024, 0, xstrdup("server-session"));
|
||||||
|
if (session_open(id) == 1) {
|
||||||
|
channel_register_callback(id, SSH2_MSG_CHANNEL_REQUEST,
|
||||||
|
session_input_channel_req, (void *)0);
|
||||||
|
channel_register_cleanup(id, session_close_by_channel);
|
||||||
|
c = channel_lookup(id);
|
||||||
|
} else {
|
||||||
|
debug("session open failed, free channel %d", id);
|
||||||
|
channel_free(id);
|
||||||
|
}
|
||||||
|
} else if (strcmp(ctype, "direct-tcpip") == 0) {
|
||||||
|
debug("open direct-tcpip");
|
||||||
|
id = input_direct_tcpip();
|
||||||
|
if (id >= 0)
|
||||||
|
c = channel_lookup(id);
|
||||||
|
}
|
||||||
|
if (c != NULL) {
|
||||||
|
debug("confirm %s", ctype);
|
||||||
|
c->remote_id = rchan;
|
||||||
|
c->remote_window = rwindow;
|
||||||
|
c->remote_maxpacket = rmaxpack;
|
||||||
|
|
||||||
|
packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
|
||||||
|
packet_put_int(c->remote_id);
|
||||||
|
packet_put_int(c->self);
|
||||||
|
packet_put_int(c->local_window);
|
||||||
|
packet_put_int(c->local_maxpacket);
|
||||||
|
packet_send();
|
||||||
|
} else {
|
||||||
|
debug("failure %s", ctype);
|
||||||
|
packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
|
||||||
|
packet_put_int(rchan);
|
||||||
|
packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
|
||||||
|
packet_put_cstring("bla bla");
|
||||||
|
packet_put_cstring("");
|
||||||
|
packet_send();
|
||||||
|
}
|
||||||
|
xfree(ctype);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
server_init_dispatch_20()
|
||||||
|
{
|
||||||
|
debug("server_init_dispatch_20");
|
||||||
|
dispatch_init(&dispatch_protocol_error);
|
||||||
|
dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose);
|
||||||
|
dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data);
|
||||||
|
dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof);
|
||||||
|
dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data);
|
||||||
|
dispatch_set(SSH2_MSG_CHANNEL_OPEN, &server_input_channel_open);
|
||||||
|
dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
|
||||||
|
dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
|
||||||
|
dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request);
|
||||||
|
dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
|
||||||
|
}
|
||||||
void
|
void
|
||||||
server_init_dispatch_13()
|
server_init_dispatch_13()
|
||||||
{
|
{
|
||||||
@ -648,7 +824,9 @@ server_init_dispatch_15()
|
|||||||
void
|
void
|
||||||
server_init_dispatch()
|
server_init_dispatch()
|
||||||
{
|
{
|
||||||
if (compat13)
|
if (compat20)
|
||||||
|
server_init_dispatch_20();
|
||||||
|
else if (compat13)
|
||||||
server_init_dispatch_13();
|
server_init_dispatch_13();
|
||||||
else
|
else
|
||||||
server_init_dispatch_15();
|
server_init_dispatch_15();
|
||||||
|
328
session.c
328
session.c
@ -2,9 +2,13 @@
|
|||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
|
* SSH2 support by Markus Friedl.
|
||||||
|
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$OpenBSD: session.c,v 1.1 2000/03/28 21:15:45 markus Exp $");
|
RCSID("$OpenBSD: session.c,v 1.2 2000/04/06 08:55:22 markus Exp $");
|
||||||
|
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
@ -19,6 +23,10 @@ RCSID("$OpenBSD: session.c,v 1.1 2000/03/28 21:15:45 markus Exp $");
|
|||||||
#include "channels.h"
|
#include "channels.h"
|
||||||
#include "nchan.h"
|
#include "nchan.h"
|
||||||
|
|
||||||
|
#include "bufaux.h"
|
||||||
|
#include "ssh2.h"
|
||||||
|
#include "auth.h"
|
||||||
|
|
||||||
/* types */
|
/* types */
|
||||||
|
|
||||||
#define TTYSZ 64
|
#define TTYSZ 64
|
||||||
@ -448,9 +456,13 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw)
|
|||||||
close(pout[1]);
|
close(pout[1]);
|
||||||
close(perr[1]);
|
close(perr[1]);
|
||||||
|
|
||||||
/* Enter the interactive session. */
|
if (compat20) {
|
||||||
server_loop(pid, pin[1], pout[0], perr[0]);
|
session_set_fds(s, pin[1], pout[0], perr[0]);
|
||||||
/* server_loop has closed pin[1], pout[1], and perr[1]. */
|
} else {
|
||||||
|
/* Enter the interactive session. */
|
||||||
|
server_loop(pid, pin[1], pout[0], perr[0]);
|
||||||
|
/* server_loop has closed pin[1], pout[1], and perr[1]. */
|
||||||
|
}
|
||||||
#else /* USE_PIPES */
|
#else /* USE_PIPES */
|
||||||
/* We are the parent. Close the child sides of the socket pairs. */
|
/* We are the parent. Close the child sides of the socket pairs. */
|
||||||
close(inout[0]);
|
close(inout[0]);
|
||||||
@ -460,8 +472,12 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw)
|
|||||||
* Enter the interactive session. Note: server_loop must be able to
|
* Enter the interactive session. Note: server_loop must be able to
|
||||||
* handle the case that fdin and fdout are the same.
|
* handle the case that fdin and fdout are the same.
|
||||||
*/
|
*/
|
||||||
server_loop(pid, inout[1], inout[1], err[1]);
|
if (compat20) {
|
||||||
/* server_loop has closed inout[1] and err[1]. */
|
session_set_fds(s, inout[1], inout[1], err[1]);
|
||||||
|
} else {
|
||||||
|
server_loop(pid, inout[1], inout[1], err[1]);
|
||||||
|
/* server_loop has closed inout[1] and err[1]. */
|
||||||
|
}
|
||||||
#endif /* USE_PIPES */
|
#endif /* USE_PIPES */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,9 +647,13 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw)
|
|||||||
s->ptymaster = ptymaster;
|
s->ptymaster = ptymaster;
|
||||||
|
|
||||||
/* Enter interactive session. */
|
/* Enter interactive session. */
|
||||||
server_loop(pid, ptyfd, fdout, -1);
|
if (compat20) {
|
||||||
/* server_loop _has_ closed ptyfd and fdout. */
|
session_set_fds(s, ptyfd, fdout, -1);
|
||||||
session_pty_cleanup(s);
|
} else {
|
||||||
|
server_loop(pid, ptyfd, fdout, -1);
|
||||||
|
/* server_loop _has_ closed ptyfd and fdout. */
|
||||||
|
session_pty_cleanup(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1126,6 +1146,181 @@ session_dump(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
session_open(int chanid)
|
||||||
|
{
|
||||||
|
Session *s = session_new();
|
||||||
|
debug("session_open: channel %d", chanid);
|
||||||
|
if (s == NULL) {
|
||||||
|
error("no more sessions");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
debug("session_open: session %d: link with channel %d", s->self, chanid);
|
||||||
|
s->chanid = chanid;
|
||||||
|
s->pw = auth_get_user();
|
||||||
|
if (s->pw == NULL)
|
||||||
|
fatal("no user for session %i channel %d",
|
||||||
|
s->self, s->chanid);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Session *
|
||||||
|
session_by_channel(int id)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < MAX_SESSIONS; i++) {
|
||||||
|
Session *s = &sessions[i];
|
||||||
|
if (s->used && s->chanid == id) {
|
||||||
|
debug("session_by_channel: session %d channel %d", i, id);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug("session_by_channel: unknown channel %d", id);
|
||||||
|
session_dump();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Session *
|
||||||
|
session_by_pid(pid_t pid)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
debug("session_by_pid: pid %d", pid);
|
||||||
|
for(i = 0; i < MAX_SESSIONS; i++) {
|
||||||
|
Session *s = &sessions[i];
|
||||||
|
if (s->used && s->pid == pid)
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
error("session_by_pid: unknown pid %d", pid);
|
||||||
|
session_dump();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
session_window_change_req(Session *s)
|
||||||
|
{
|
||||||
|
s->col = packet_get_int();
|
||||||
|
s->row = packet_get_int();
|
||||||
|
s->xpixel = packet_get_int();
|
||||||
|
s->ypixel = packet_get_int();
|
||||||
|
pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
session_pty_req(Session *s)
|
||||||
|
{
|
||||||
|
unsigned int len;
|
||||||
|
|
||||||
|
if (s->ttyfd != -1)
|
||||||
|
return -1;
|
||||||
|
s->term = packet_get_string(&len);
|
||||||
|
s->col = packet_get_int();
|
||||||
|
s->row = packet_get_int();
|
||||||
|
s->xpixel = packet_get_int();
|
||||||
|
s->ypixel = packet_get_int();
|
||||||
|
|
||||||
|
if (strcmp(s->term, "") == 0) {
|
||||||
|
xfree(s->term);
|
||||||
|
s->term = NULL;
|
||||||
|
}
|
||||||
|
/* Allocate a pty and open it. */
|
||||||
|
if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) {
|
||||||
|
xfree(s->term);
|
||||||
|
s->term = NULL;
|
||||||
|
s->ptyfd = -1;
|
||||||
|
s->ttyfd = -1;
|
||||||
|
error("session_pty_req: session %d alloc failed", s->self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
debug("session_pty_req: session %d alloc %s", s->self, s->tty);
|
||||||
|
/*
|
||||||
|
* Add a cleanup function to clear the utmp entry and record logout
|
||||||
|
* time in case we call fatal() (e.g., the connection gets closed).
|
||||||
|
*/
|
||||||
|
fatal_add_cleanup(pty_cleanup_proc, (void *)s);
|
||||||
|
pty_setowner(s->pw, s->tty);
|
||||||
|
/* Get window size from the packet. */
|
||||||
|
pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
session_input_channel_req(int id, void *arg)
|
||||||
|
{
|
||||||
|
unsigned int len;
|
||||||
|
int reply;
|
||||||
|
int success = 0;
|
||||||
|
char *rtype;
|
||||||
|
Session *s;
|
||||||
|
Channel *c;
|
||||||
|
|
||||||
|
rtype = packet_get_string(&len);
|
||||||
|
reply = packet_get_char();
|
||||||
|
|
||||||
|
s = session_by_channel(id);
|
||||||
|
if (s == NULL)
|
||||||
|
fatal("session_input_channel_req: channel %d: no session", id);
|
||||||
|
c = channel_lookup(id);
|
||||||
|
if (c == NULL)
|
||||||
|
fatal("session_input_channel_req: channel %d: bad channel", id);
|
||||||
|
|
||||||
|
debug("session_input_channel_req: session %d channel %d request %s reply %d",
|
||||||
|
s->self, id, rtype, reply);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* a session is in LARVAL state until a shell
|
||||||
|
* or programm is executed
|
||||||
|
*/
|
||||||
|
if (c->type == SSH_CHANNEL_LARVAL) {
|
||||||
|
if (strcmp(rtype, "shell") == 0) {
|
||||||
|
if (s->ttyfd == -1)
|
||||||
|
do_exec_no_pty(s, NULL, s->pw);
|
||||||
|
else
|
||||||
|
do_exec_pty(s, NULL, s->pw);
|
||||||
|
success = 1;
|
||||||
|
} else if (strcmp(rtype, "exec") == 0) {
|
||||||
|
char *command = packet_get_string(&len);
|
||||||
|
if (s->ttyfd == -1)
|
||||||
|
do_exec_no_pty(s, command, s->pw);
|
||||||
|
else
|
||||||
|
do_exec_pty(s, command, s->pw);
|
||||||
|
xfree(command);
|
||||||
|
success = 1;
|
||||||
|
} else if (strcmp(rtype, "pty-req") == 0) {
|
||||||
|
if (session_pty_req(s) > 0)
|
||||||
|
success = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (strcmp(rtype, "window-change") == 0) {
|
||||||
|
success = session_window_change_req(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reply) {
|
||||||
|
packet_start(success ?
|
||||||
|
SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
|
||||||
|
packet_put_int(c->remote_id);
|
||||||
|
packet_send();
|
||||||
|
}
|
||||||
|
xfree(rtype);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
session_set_fds(Session *s, int fdin, int fdout, int fderr)
|
||||||
|
{
|
||||||
|
if (!compat20)
|
||||||
|
fatal("session_set_fds: called for proto != 2.0");
|
||||||
|
/*
|
||||||
|
* now that have a child and a pipe to the child,
|
||||||
|
* we can activate our channel and register the fd's
|
||||||
|
*/
|
||||||
|
if (s->chanid == -1)
|
||||||
|
fatal("no channel for session %d", s->self);
|
||||||
|
channel_set_fds(s->chanid,
|
||||||
|
fdout, fdin, fderr,
|
||||||
|
fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
session_pty_cleanup(Session *s)
|
session_pty_cleanup(Session *s)
|
||||||
{
|
{
|
||||||
@ -1151,3 +1346,118 @@ session_pty_cleanup(Session *s)
|
|||||||
if (close(s->ptymaster) < 0)
|
if (close(s->ptymaster) < 0)
|
||||||
error("close(s->ptymaster): %s", strerror(errno));
|
error("close(s->ptymaster): %s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
session_exit_message(Session *s, int status)
|
||||||
|
{
|
||||||
|
Channel *c;
|
||||||
|
if (s == NULL)
|
||||||
|
fatal("session_close: no session");
|
||||||
|
c = channel_lookup(s->chanid);
|
||||||
|
if (c == NULL)
|
||||||
|
fatal("session_close: session %d: no channel %d",
|
||||||
|
s->self, s->chanid);
|
||||||
|
debug("session_exit_message: session %d channel %d pid %d",
|
||||||
|
s->self, s->chanid, s->pid);
|
||||||
|
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
channel_request_start(s->chanid,
|
||||||
|
"exit-status", 0);
|
||||||
|
packet_put_int(WEXITSTATUS(status));
|
||||||
|
packet_send();
|
||||||
|
} else if (WIFSIGNALED(status)) {
|
||||||
|
channel_request_start(s->chanid,
|
||||||
|
"exit-signal", 0);
|
||||||
|
packet_put_int(WTERMSIG(status));
|
||||||
|
packet_put_char(WCOREDUMP(status));
|
||||||
|
packet_put_cstring("");
|
||||||
|
packet_put_cstring("");
|
||||||
|
packet_send();
|
||||||
|
} else {
|
||||||
|
/* Some weird exit cause. Just exit. */
|
||||||
|
packet_disconnect("wait returned status %04x.", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* disconnect channel */
|
||||||
|
debug("session_exit_message: release channel %d", s->chanid);
|
||||||
|
channel_cancel_cleanup(s->chanid);
|
||||||
|
if (c->istate == CHAN_INPUT_OPEN)
|
||||||
|
chan_read_failed(c);
|
||||||
|
chan_write_failed(c);
|
||||||
|
s->chanid = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
session_free(Session *s)
|
||||||
|
{
|
||||||
|
debug("session_free: session %d pid %d", s->self, s->pid);
|
||||||
|
if (s->term)
|
||||||
|
xfree(s->term);
|
||||||
|
if (s->display)
|
||||||
|
xfree(s->display);
|
||||||
|
if (s->auth_data)
|
||||||
|
xfree(s->auth_data);
|
||||||
|
if (s->auth_proto)
|
||||||
|
xfree(s->auth_proto);
|
||||||
|
s->used = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
session_close(Session *s)
|
||||||
|
{
|
||||||
|
session_pty_cleanup(s);
|
||||||
|
session_free(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
session_close_by_pid(pid_t pid, int status)
|
||||||
|
{
|
||||||
|
Session *s = session_by_pid(pid);
|
||||||
|
if (s == NULL) {
|
||||||
|
debug("session_close_by_pid: no session for pid %d", s->pid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (s->chanid != -1)
|
||||||
|
session_exit_message(s, status);
|
||||||
|
session_close(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this is called when a channel dies before
|
||||||
|
* the session 'child' itself dies
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
session_close_by_channel(int id, void *arg)
|
||||||
|
{
|
||||||
|
Session *s = session_by_channel(id);
|
||||||
|
if (s == NULL) {
|
||||||
|
debug("session_close_by_channel: no session for channel %d", id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* disconnect channel */
|
||||||
|
channel_cancel_cleanup(s->chanid);
|
||||||
|
s->chanid = -1;
|
||||||
|
|
||||||
|
debug("session_close_by_channel: channel %d kill %d", id, s->pid);
|
||||||
|
if (s->pid == 0) {
|
||||||
|
/* close session immediately */
|
||||||
|
session_close(s);
|
||||||
|
} else {
|
||||||
|
/* notify child, delay session cleanup */
|
||||||
|
if (kill(s->pid, (s->ttyfd == -1) ? SIGTERM : SIGHUP) < 0)
|
||||||
|
error("session_close_by_channel: kill %d: %s",
|
||||||
|
s->pid, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
do_authenticated2(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Cancel the alarm we set to limit the time taken for
|
||||||
|
* authentication.
|
||||||
|
*/
|
||||||
|
alarm(0);
|
||||||
|
log("do_authenticated2");
|
||||||
|
server_loop2();
|
||||||
|
}
|
||||||
|
@ -4,4 +4,11 @@
|
|||||||
/* SSH1 */
|
/* SSH1 */
|
||||||
void do_authenticated(struct passwd * pw);
|
void do_authenticated(struct passwd * pw);
|
||||||
|
|
||||||
|
/* SSH2 */
|
||||||
|
void do_authenticated2(void);
|
||||||
|
int session_open(int id);
|
||||||
|
void session_input_channel_req(int id, void *arg);
|
||||||
|
void session_close_by_pid(pid_t pid, int status);
|
||||||
|
void session_close_by_channel(int id, void *arg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
6
ssh.h
6
ssh.h
@ -13,7 +13,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* RCSID("$Id: ssh.h,v 1.29 2000/04/01 01:09:26 damien Exp $"); */
|
/* RCSID("$Id: ssh.h,v 1.30 2000/04/12 08:45:07 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef SSH_H
|
#ifndef SSH_H
|
||||||
#define SSH_H
|
#define SSH_H
|
||||||
@ -90,6 +90,7 @@
|
|||||||
#define HOST_KEY_FILE ETCDIR "/ssh_host_key"
|
#define HOST_KEY_FILE ETCDIR "/ssh_host_key"
|
||||||
#define SERVER_CONFIG_FILE ETCDIR "/sshd_config"
|
#define SERVER_CONFIG_FILE ETCDIR "/sshd_config"
|
||||||
#define HOST_CONFIG_FILE ETCDIR "/ssh_config"
|
#define HOST_CONFIG_FILE ETCDIR "/ssh_config"
|
||||||
|
#define DSA_KEY_FILE ETCDIR "/ssh_dsa_key"
|
||||||
|
|
||||||
#ifndef SSH_PROGRAM
|
#ifndef SSH_PROGRAM
|
||||||
#define SSH_PROGRAM "/usr/bin/ssh"
|
#define SSH_PROGRAM "/usr/bin/ssh"
|
||||||
@ -486,6 +487,8 @@ void fatal_add_cleanup(void (*proc) (void *context), void *context);
|
|||||||
/* Removes a cleanup function to be called at fatal(). */
|
/* Removes a cleanup function to be called at fatal(). */
|
||||||
void fatal_remove_cleanup(void (*proc) (void *context), void *context);
|
void fatal_remove_cleanup(void (*proc) (void *context), void *context);
|
||||||
|
|
||||||
|
/* ---- misc */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expands tildes in the file name. Returns data allocated by xmalloc.
|
* Expands tildes in the file name. Returns data allocated by xmalloc.
|
||||||
* Warning: this calls getpw*.
|
* Warning: this calls getpw*.
|
||||||
@ -500,6 +503,7 @@ char *tilde_expand_filename(const char *filename, uid_t my_uid);
|
|||||||
* program).
|
* program).
|
||||||
*/
|
*/
|
||||||
void server_loop(int pid, int fdin, int fdout, int fderr);
|
void server_loop(int pid, int fdin, int fdout, int fderr);
|
||||||
|
void server_loop2(void);
|
||||||
|
|
||||||
/* Client side main loop for the interactive session. */
|
/* Client side main loop for the interactive session. */
|
||||||
int client_loop(int have_pty, int escape_char);
|
int client_loop(int have_pty, int escape_char);
|
||||||
|
240
sshd.c
240
sshd.c
@ -8,10 +8,13 @@
|
|||||||
* information to/from the application to the user client over an encrypted
|
* information to/from the application to the user client over an encrypted
|
||||||
* connection. This can also handle forwarding of X11, TCP/IP, and authentication
|
* connection. This can also handle forwarding of X11, TCP/IP, and authentication
|
||||||
* agent connections.
|
* agent connections.
|
||||||
|
*
|
||||||
|
* SSH2 implementation,
|
||||||
|
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$OpenBSD: sshd.c,v 1.97 2000/04/04 21:37:27 markus Exp $");
|
RCSID("$OpenBSD: sshd.c,v 1.99 2000/04/07 09:17:39 markus Exp $");
|
||||||
|
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "rsa.h"
|
#include "rsa.h"
|
||||||
@ -25,6 +28,7 @@ RCSID("$OpenBSD: sshd.c,v 1.97 2000/04/04 21:37:27 markus Exp $");
|
|||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
|
||||||
|
#include "ssh2.h"
|
||||||
#ifdef HAVE_OPENSSL
|
#ifdef HAVE_OPENSSL
|
||||||
# include <openssl/dh.h>
|
# include <openssl/dh.h>
|
||||||
# include <openssl/bn.h>
|
# include <openssl/bn.h>
|
||||||
@ -39,9 +43,12 @@ RCSID("$OpenBSD: sshd.c,v 1.97 2000/04/04 21:37:27 markus Exp $");
|
|||||||
# include <ssl/dsa.h>
|
# include <ssl/dsa.h>
|
||||||
# include <ssl/rsa.h>
|
# include <ssl/rsa.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include "kex.h"
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
|
#include "dsa.h"
|
||||||
|
|
||||||
#include "auth.h"
|
#include "auth.h"
|
||||||
|
#include "myproposal.h"
|
||||||
|
|
||||||
#ifdef LIBWRAP
|
#ifdef LIBWRAP
|
||||||
#include <tcpd.h>
|
#include <tcpd.h>
|
||||||
@ -70,6 +77,9 @@ int IPv4or6 = AF_INET;
|
|||||||
int IPv4or6 = AF_UNSPEC;
|
int IPv4or6 = AF_UNSPEC;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Flag indicating whether SSH2 is enabled */
|
||||||
|
int allow_ssh2 = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Debug mode flag. This can be set on the command line. If debug
|
* Debug mode flag. This can be set on the command line. If debug
|
||||||
* mode is enabled, extra debugging output will be sent to the system
|
* mode is enabled, extra debugging output will be sent to the system
|
||||||
@ -136,6 +146,7 @@ unsigned char session_id[16];
|
|||||||
|
|
||||||
/* Prototypes for various functions defined later in this file. */
|
/* Prototypes for various functions defined later in this file. */
|
||||||
void do_ssh1_kex();
|
void do_ssh1_kex();
|
||||||
|
void do_ssh2_kex();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close all listening sockets
|
* Close all listening sockets
|
||||||
@ -255,6 +266,21 @@ key_regeneration_alarm(int sig)
|
|||||||
errno = save_errno;
|
errno = save_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
chop(char *s)
|
||||||
|
{
|
||||||
|
char *t = s;
|
||||||
|
while (*t) {
|
||||||
|
if(*t == '\n' || *t == '\r') {
|
||||||
|
*t = '\0';
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
t++;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sshd_exchange_identification(int sock_in, int sock_out)
|
sshd_exchange_identification(int sock_in, int sock_out)
|
||||||
{
|
{
|
||||||
@ -265,7 +291,9 @@ sshd_exchange_identification(int sock_in, int sock_out)
|
|||||||
char remote_version[256]; /* Must be at least as big as buf. */
|
char remote_version[256]; /* Must be at least as big as buf. */
|
||||||
|
|
||||||
snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
|
snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
|
||||||
PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION);
|
allow_ssh2 ? 1 : PROTOCOL_MAJOR,
|
||||||
|
allow_ssh2 ? 99 : PROTOCOL_MINOR,
|
||||||
|
SSH_VERSION);
|
||||||
server_version_string = xstrdup(buf);
|
server_version_string = xstrdup(buf);
|
||||||
|
|
||||||
if (client_version_string == NULL) {
|
if (client_version_string == NULL) {
|
||||||
@ -286,7 +314,7 @@ sshd_exchange_identification(int sock_in, int sock_out)
|
|||||||
buf[i] = '\n';
|
buf[i] = '\n';
|
||||||
buf[i + 1] = 0;
|
buf[i + 1] = 0;
|
||||||
continue;
|
continue;
|
||||||
/*break; XXX eat \r */
|
//break;
|
||||||
}
|
}
|
||||||
if (buf[i] == '\n') {
|
if (buf[i] == '\n') {
|
||||||
/* buf[i] == '\n' */
|
/* buf[i] == '\n' */
|
||||||
@ -315,6 +343,8 @@ sshd_exchange_identification(int sock_in, int sock_out)
|
|||||||
debug("Client protocol version %d.%d; client software version %.100s",
|
debug("Client protocol version %d.%d; client software version %.100s",
|
||||||
remote_major, remote_minor, remote_version);
|
remote_major, remote_minor, remote_version);
|
||||||
|
|
||||||
|
compat_datafellows(remote_version);
|
||||||
|
|
||||||
switch(remote_major) {
|
switch(remote_major) {
|
||||||
case 1:
|
case 1:
|
||||||
if (remote_minor < 3) {
|
if (remote_minor < 3) {
|
||||||
@ -324,7 +354,15 @@ sshd_exchange_identification(int sock_in, int sock_out)
|
|||||||
/* note that this disables agent-forwarding */
|
/* note that this disables agent-forwarding */
|
||||||
enable_compat13();
|
enable_compat13();
|
||||||
}
|
}
|
||||||
break;
|
if (remote_minor != 99)
|
||||||
|
break;
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case 2:
|
||||||
|
if (allow_ssh2) {
|
||||||
|
enable_compat20();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* FALLTHROUGH */
|
||||||
default:
|
default:
|
||||||
s = "Protocol major versions differ.\n";
|
s = "Protocol major versions differ.\n";
|
||||||
(void) atomicio(write, sock_out, s, strlen(s));
|
(void) atomicio(write, sock_out, s, strlen(s));
|
||||||
@ -335,6 +373,8 @@ sshd_exchange_identification(int sock_in, int sock_out)
|
|||||||
fatal_cleanup();
|
fatal_cleanup();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
chop(server_version_string);
|
||||||
|
chop(client_version_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -370,8 +410,11 @@ main(int ac, char **av)
|
|||||||
initialize_server_options(&options);
|
initialize_server_options(&options);
|
||||||
|
|
||||||
/* Parse command-line arguments. */
|
/* Parse command-line arguments. */
|
||||||
while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ46")) != EOF) {
|
while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ246")) != EOF) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
|
case '2':
|
||||||
|
allow_ssh2 = 1;
|
||||||
|
break;
|
||||||
case '4':
|
case '4':
|
||||||
IPv4or6 = AF_INET;
|
IPv4or6 = AF_INET;
|
||||||
break;
|
break;
|
||||||
@ -837,9 +880,14 @@ main(int ac, char **av)
|
|||||||
packet_set_nonblocking();
|
packet_set_nonblocking();
|
||||||
|
|
||||||
/* perform the key exchange */
|
/* perform the key exchange */
|
||||||
do_ssh1_kex();
|
|
||||||
/* authenticate user and start session */
|
/* authenticate user and start session */
|
||||||
do_authentication();
|
if (compat20) {
|
||||||
|
do_ssh2_kex();
|
||||||
|
do_authentication2();
|
||||||
|
} else {
|
||||||
|
do_ssh1_kex();
|
||||||
|
do_authentication();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef KRB4
|
#ifdef KRB4
|
||||||
/* Cleanup user's ticket cache file. */
|
/* Cleanup user's ticket cache file. */
|
||||||
@ -1049,3 +1097,181 @@ do_ssh1_kex()
|
|||||||
packet_send();
|
packet_send();
|
||||||
packet_write_wait();
|
packet_write_wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SSH2 key exchange: diffie-hellman-group1-sha1
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
do_ssh2_kex()
|
||||||
|
{
|
||||||
|
Buffer *server_kexinit;
|
||||||
|
Buffer *client_kexinit;
|
||||||
|
int payload_len, dlen;
|
||||||
|
int slen;
|
||||||
|
unsigned int klen, kout;
|
||||||
|
char *ptr;
|
||||||
|
unsigned char *signature = NULL;
|
||||||
|
unsigned char *server_host_key_blob = NULL;
|
||||||
|
unsigned int sbloblen;
|
||||||
|
DH *dh;
|
||||||
|
BIGNUM *dh_client_pub = 0;
|
||||||
|
BIGNUM *shared_secret = 0;
|
||||||
|
int i;
|
||||||
|
unsigned char *kbuf;
|
||||||
|
unsigned char *hash;
|
||||||
|
Kex *kex;
|
||||||
|
Key *server_host_key;
|
||||||
|
char *cprop[PROPOSAL_MAX];
|
||||||
|
char *sprop[PROPOSAL_MAX];
|
||||||
|
|
||||||
|
/* KEXINIT */
|
||||||
|
|
||||||
|
debug("Sending KEX init.");
|
||||||
|
|
||||||
|
for (i = 0; i < PROPOSAL_MAX; i++)
|
||||||
|
sprop[i] = xstrdup(myproposal[i]);
|
||||||
|
server_kexinit = kex_init(sprop);
|
||||||
|
packet_start(SSH2_MSG_KEXINIT);
|
||||||
|
packet_put_raw(buffer_ptr(server_kexinit), buffer_len(server_kexinit));
|
||||||
|
packet_send();
|
||||||
|
packet_write_wait();
|
||||||
|
|
||||||
|
debug("done");
|
||||||
|
|
||||||
|
packet_read_expect(&payload_len, SSH2_MSG_KEXINIT);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* save raw KEXINIT payload in buffer. this is used during
|
||||||
|
* computation of the session_id and the session keys.
|
||||||
|
*/
|
||||||
|
client_kexinit = xmalloc(sizeof(*client_kexinit));
|
||||||
|
buffer_init(client_kexinit);
|
||||||
|
ptr = packet_get_raw(&payload_len);
|
||||||
|
buffer_append(client_kexinit, ptr, payload_len);
|
||||||
|
|
||||||
|
/* skip cookie */
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
(void) packet_get_char();
|
||||||
|
/* save kex init proposal strings */
|
||||||
|
for (i = 0; i < PROPOSAL_MAX; i++) {
|
||||||
|
cprop[i] = packet_get_string(NULL);
|
||||||
|
debug("got kexinit string: %s", cprop[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
i = (int) packet_get_char();
|
||||||
|
debug("first kex follow == %d", i);
|
||||||
|
i = packet_get_int();
|
||||||
|
debug("reserved == %d", i);
|
||||||
|
|
||||||
|
debug("done read kexinit");
|
||||||
|
kex = kex_choose_conf(cprop, sprop, 1);
|
||||||
|
|
||||||
|
/* KEXDH */
|
||||||
|
|
||||||
|
debug("Wait SSH2_MSG_KEXDH_INIT.");
|
||||||
|
packet_read_expect(&payload_len, SSH2_MSG_KEXDH_INIT);
|
||||||
|
|
||||||
|
/* key, cert */
|
||||||
|
dh_client_pub = BN_new();
|
||||||
|
if (dh_client_pub == NULL)
|
||||||
|
fatal("dh_client_pub == NULL");
|
||||||
|
packet_get_bignum2(dh_client_pub, &dlen);
|
||||||
|
|
||||||
|
#ifdef DEBUG_KEXDH
|
||||||
|
fprintf(stderr, "\ndh_client_pub= ");
|
||||||
|
bignum_print(dh_client_pub);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
debug("bits %d", BN_num_bits(dh_client_pub));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* generate DH key */
|
||||||
|
dh = new_dh_group1(); /* XXX depends on 'kex' */
|
||||||
|
|
||||||
|
#ifdef DEBUG_KEXDH
|
||||||
|
fprintf(stderr, "\np= ");
|
||||||
|
bignum_print(dh->p);
|
||||||
|
fprintf(stderr, "\ng= ");
|
||||||
|
bignum_print(dh->g);
|
||||||
|
fprintf(stderr, "\npub= ");
|
||||||
|
bignum_print(dh->pub_key);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
klen = DH_size(dh);
|
||||||
|
kbuf = xmalloc(klen);
|
||||||
|
kout = DH_compute_key(kbuf, dh_client_pub, dh);
|
||||||
|
|
||||||
|
#ifdef DEBUG_KEXDH
|
||||||
|
debug("shared secret: len %d/%d", klen, kout);
|
||||||
|
fprintf(stderr, "shared secret == ");
|
||||||
|
for (i = 0; i< kout; i++)
|
||||||
|
fprintf(stderr, "%02x", (kbuf[i])&0xff);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
#endif
|
||||||
|
shared_secret = BN_new();
|
||||||
|
|
||||||
|
BN_bin2bn(kbuf, kout, shared_secret);
|
||||||
|
memset(kbuf, 0, klen);
|
||||||
|
xfree(kbuf);
|
||||||
|
|
||||||
|
server_host_key = dsa_get_serverkey(options.dsa_key_file);
|
||||||
|
dsa_make_serverkey_blob(server_host_key, &server_host_key_blob, &sbloblen);
|
||||||
|
|
||||||
|
/* calc H */ /* XXX depends on 'kex' */
|
||||||
|
hash = kex_hash(
|
||||||
|
client_version_string,
|
||||||
|
server_version_string,
|
||||||
|
buffer_ptr(client_kexinit), buffer_len(client_kexinit),
|
||||||
|
buffer_ptr(server_kexinit), buffer_len(server_kexinit),
|
||||||
|
(char *)server_host_key_blob, sbloblen,
|
||||||
|
dh_client_pub,
|
||||||
|
dh->pub_key,
|
||||||
|
shared_secret
|
||||||
|
);
|
||||||
|
buffer_free(client_kexinit);
|
||||||
|
buffer_free(server_kexinit);
|
||||||
|
xfree(client_kexinit);
|
||||||
|
xfree(server_kexinit);
|
||||||
|
#ifdef DEBUG_KEXDH
|
||||||
|
fprintf(stderr, "hash == ");
|
||||||
|
for (i = 0; i< 20; i++)
|
||||||
|
fprintf(stderr, "%02x", (hash[i])&0xff);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
#endif
|
||||||
|
/* sign H */
|
||||||
|
dsa_sign(server_host_key, &signature, &slen, hash, 20);
|
||||||
|
/* hashlen depends on KEX */
|
||||||
|
key_free(server_host_key);
|
||||||
|
|
||||||
|
/* send server hostkey, DH pubkey 'f' and singed H */
|
||||||
|
packet_start(SSH2_MSG_KEXDH_REPLY);
|
||||||
|
packet_put_string((char *)server_host_key_blob, sbloblen);
|
||||||
|
packet_put_bignum2(dh->pub_key); // f
|
||||||
|
packet_put_string((char *)signature, slen);
|
||||||
|
packet_send();
|
||||||
|
packet_write_wait();
|
||||||
|
|
||||||
|
kex_derive_keys(kex, hash, shared_secret);
|
||||||
|
packet_set_kex(kex);
|
||||||
|
|
||||||
|
/* have keys, free DH */
|
||||||
|
DH_free(dh);
|
||||||
|
|
||||||
|
debug("send SSH2_MSG_NEWKEYS.");
|
||||||
|
packet_start(SSH2_MSG_NEWKEYS);
|
||||||
|
packet_send();
|
||||||
|
packet_write_wait();
|
||||||
|
debug("done: send SSH2_MSG_NEWKEYS.");
|
||||||
|
|
||||||
|
debug("Wait SSH2_MSG_NEWKEYS.");
|
||||||
|
packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS);
|
||||||
|
debug("GOT SSH2_MSG_NEWKEYS.");
|
||||||
|
|
||||||
|
/* send 1st encrypted/maced/compressed message */
|
||||||
|
packet_start(SSH2_MSG_IGNORE);
|
||||||
|
packet_put_cstring("markus");
|
||||||
|
packet_send();
|
||||||
|
packet_write_wait();
|
||||||
|
|
||||||
|
debug("done: KEX2.");
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user