This commit was generated by cvs2svn to compensate for changes in r60573,

which included commits to RCS files with non-trunk default branches.
This commit is contained in:
Kris Kennaway 2000-05-15 04:37:24 +00:00
commit fe01acb846
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=60574
70 changed files with 9149 additions and 1571 deletions

View File

@ -0,0 +1,44 @@
$Id: README.openssh2,v 1.8 2000/05/07 18:30:03 markus Exp $
howto:
1) generate server key:
$ ssh-keygen -d -f /etc/ssh_host_dsa_key -N ''
2) enable ssh2:
server: add 'Protocol 2,1' to /etc/sshd_config
client: ssh -o 'Protocol 2,1', or add to .ssh/config
3) DSA authentication similar to RSA (add keys to ~/.ssh/authorized_keys2)
interop w/ ssh.com dsa-keys:
ssh-keygen -f /key/from/ssh.com -X >> ~/.ssh/authorized_keys2
and vice versa
ssh-keygen -f /privatekey/from/openssh -x > ~/.ssh2/mykey.pub
echo Key mykey.pub >> ~/.ssh2/authorization
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 and pubkey with DSA
secsh-connection: pty+shell or command, flow control works (window adjust)
tcp-forwarding: -L works, -R incomplete
x11-fwd
dss/dsa: host key database in ~/.ssh/known_hosts2
client interops w/ sshd2, lshd
server interops w/ ssh2, lsh, ssh.com's Windows client, SecureCRT, F-Secure SSH Client 4.0, SecureFX (secure ftp)
server supports multiple concurrent sessions (e.g. with SSH.com Windows client)
todo:
re-keying
secsh-connection features:
tcp-forwarding, agent-fwd
auth other than passwd, and DSA-pubkey:
keyboard-interactive, (PGP-pubkey?)
config
server-auth w/ old host-keys
cleanup
advanced key storage?
keynote
sftp
-markus
$Date: 2000/05/07 18:30:03 $

View File

@ -1,22 +1,22 @@
/*
*
*
* auth-rhosts.c
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Fri Mar 17 05:12:18 1995 ylo
*
*
* Rhosts authentication. This file contains code to check whether to admit
* the login based on rhosts authentication. This file also processes
* /etc/hosts.equiv.
*
*
*/
#include "includes.h"
RCSID("$Id: auth-rhosts.c,v 1.12 1999/12/27 10:46:11 markus Exp $");
RCSID("$Id: auth-rhosts.c,v 1.13 2000/04/14 10:30:29 markus Exp $");
#include "packet.h"
#include "ssh.h"
@ -30,7 +30,7 @@ RCSID("$Id: auth-rhosts.c,v 1.12 1999/12/27 10:46:11 markus Exp $");
* based on the file, and returns zero otherwise.
*/
int
int
check_rhosts_file(const char *filename, const char *hostname,
const char *ipaddr, const char *client_user,
const char *server_user)
@ -146,7 +146,7 @@ check_rhosts_file(const char *filename, const char *hostname,
* /etc/hosts.equiv will be considered (.rhosts and .shosts are ignored).
*/
int
int
auth_rhosts(struct passwd *pw, const char *client_user)
{
extern ServerOptions options;

View File

@ -1,16 +1,16 @@
#include "includes.h"
RCSID("$Id: auth-skey.c,v 1.5 1999/12/06 19:04:57 deraadt Exp $");
RCSID("$Id: auth-skey.c,v 1.6 2000/04/14 10:30:29 markus Exp $");
#include "ssh.h"
#include "packet.h"
#include <sha1.h>
/*
/*
* try skey authentication,
* return 1 on success, 0 on failure, -1 if skey is not available
* return 1 on success, 0 on failure, -1 if skey is not available
*/
int
int
auth_skey_password(struct passwd * pw, const char *password)
{
if (strncasecmp(password, "s/key", 5) == 0) {
@ -43,18 +43,18 @@ auth_skey_password(struct passwd * pw, const char *password)
*/
static u_int32_t
hash_collapse(s)
u_char *s;
u_char *s;
{
int len, target;
int len, target;
u_int32_t i;
if ((strlen(s) % sizeof(u_int32_t)) == 0)
target = strlen(s); /* Multiple of 4 */
target = strlen(s); /* Multiple of 4 */
else
target = strlen(s) - (strlen(s) % sizeof(u_int32_t));
for (i = 0, len = 0; len < target; len += 4)
i ^= ROUND(s + len);
i ^= ROUND(s + len);
return i;
}

111
crypto/openssh/auth.c Normal file
View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*/
#include "includes.h"
RCSID("$OpenBSD: auth.c,v 1.6 2000/04/26 21:28:31 markus Exp $");
#include "xmalloc.h"
#include "rsa.h"
#include "ssh.h"
#include "pty.h"
#include "packet.h"
#include "buffer.h"
#include "cipher.h"
#include "mpaux.h"
#include "servconf.h"
#include "compat.h"
#include "channels.h"
#include "match.h"
#include "bufaux.h"
#include "ssh2.h"
#include "auth.h"
#include "session.h"
#include "dispatch.h"
/* import */
extern ServerOptions options;
extern char *forced_command;
/*
* Check if the user is allowed to log in via ssh. If user is listed in
* DenyUsers or user's primary group is listed in DenyGroups, false will
* be returned. If AllowUsers isn't empty and user isn't listed there, or
* if AllowGroups isn't empty and user isn't listed there, false will be
* returned.
* If the user's shell is not executable, false will be returned.
* Otherwise true is returned.
*/
int
allowed_user(struct passwd * pw)
{
struct stat st;
struct group *grp;
int i;
/* Shouldn't be called if pw is NULL, but better safe than sorry... */
if (!pw)
return 0;
/* deny if shell does not exists or is not executable */
if (stat(pw->pw_shell, &st) != 0)
return 0;
if (!((st.st_mode & S_IFREG) && (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP))))
return 0;
/* Return false if user is listed in DenyUsers */
if (options.num_deny_users > 0) {
if (!pw->pw_name)
return 0;
for (i = 0; i < options.num_deny_users; i++)
if (match_pattern(pw->pw_name, options.deny_users[i]))
return 0;
}
/* Return false if AllowUsers isn't empty and user isn't listed there */
if (options.num_allow_users > 0) {
if (!pw->pw_name)
return 0;
for (i = 0; i < options.num_allow_users; i++)
if (match_pattern(pw->pw_name, options.allow_users[i]))
break;
/* i < options.num_allow_users iff we break for loop */
if (i >= options.num_allow_users)
return 0;
}
/* Get the primary group name if we need it. Return false if it fails */
if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
grp = getgrgid(pw->pw_gid);
if (!grp)
return 0;
/* Return false if user's group is listed in DenyGroups */
if (options.num_deny_groups > 0) {
if (!grp->gr_name)
return 0;
for (i = 0; i < options.num_deny_groups; i++)
if (match_pattern(grp->gr_name, options.deny_groups[i]))
return 0;
}
/*
* Return false if AllowGroups isn't empty and user's group
* isn't listed there
*/
if (options.num_allow_groups > 0) {
if (!grp->gr_name)
return 0;
for (i = 0; i < options.num_allow_groups; i++)
if (match_pattern(grp->gr_name, options.allow_groups[i]))
break;
/* i < options.num_allow_groups iff we break for
loop */
if (i >= options.num_allow_groups)
return 0;
}
}
/* We found no reason not to let this user try to log on... */
return 1;
}

17
crypto/openssh/auth.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef AUTH_H
#define AUTH_H
void do_authentication(void);
void do_authentication2(void);
struct passwd *
auth_get_user(void);
int allowed_user(struct passwd * pw);;
#define AUTH_FAIL_MAX 6
#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
#endif

468
crypto/openssh/auth1.c Normal file
View File

@ -0,0 +1,468 @@
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*/
#include "includes.h"
RCSID("$OpenBSD: auth1.c,v 1.2 2000/04/29 18:11:52 markus Exp $");
#include "xmalloc.h"
#include "rsa.h"
#include "ssh.h"
#include "packet.h"
#include "buffer.h"
#include "cipher.h"
#include "mpaux.h"
#include "servconf.h"
#include "compat.h"
#include "auth.h"
#include "session.h"
/* import */
extern ServerOptions options;
extern char *forced_command;
/*
* convert ssh auth msg type into description
*/
char *
get_authname(int type)
{
static char buf[1024];
switch (type) {
case SSH_CMSG_AUTH_PASSWORD:
return "password";
case SSH_CMSG_AUTH_RSA:
return "rsa";
case SSH_CMSG_AUTH_RHOSTS_RSA:
return "rhosts-rsa";
case SSH_CMSG_AUTH_RHOSTS:
return "rhosts";
#ifdef KRB4
case SSH_CMSG_AUTH_KERBEROS:
return "kerberos";
#endif
#ifdef SKEY
case SSH_CMSG_AUTH_TIS_RESPONSE:
return "s/key";
#endif
}
snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
return buf;
}
/*
* The user does not exist or access is denied,
* but fake indication that authentication is needed.
*/
void
do_fake_authloop1(char *user)
{
int attempt = 0;
log("Faking authloop for illegal user %.200s from %.200s port %d",
user,
get_remote_ipaddr(),
get_remote_port());
/* Indicate that authentication is needed. */
packet_start(SSH_SMSG_FAILURE);
packet_send();
packet_write_wait();
/*
* Keep reading packets, and always respond with a failure. This is
* to avoid disclosing whether such a user really exists.
*/
for (attempt = 1;; attempt++) {
/* Read a packet. This will not return if the client disconnects. */
int plen;
int type = packet_read(&plen);
#ifdef SKEY
unsigned int dlen;
char *password, *skeyinfo;
password = NULL;
/* Try to send a fake s/key challenge. */
if (options.skey_authentication == 1 &&
(skeyinfo = skey_fake_keyinfo(user)) != NULL) {
if (type == SSH_CMSG_AUTH_TIS) {
packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
packet_put_string(skeyinfo, strlen(skeyinfo));
packet_send();
packet_write_wait();
continue;
} else if (type == SSH_CMSG_AUTH_PASSWORD &&
options.password_authentication &&
(password = packet_get_string(&dlen)) != NULL &&
dlen == 5 &&
strncasecmp(password, "s/key", 5) == 0 ) {
packet_send_debug(skeyinfo);
}
}
if (password != NULL)
xfree(password);
#endif
if (attempt > AUTH_FAIL_MAX)
packet_disconnect(AUTH_FAIL_MSG, user);
/*
* Send failure. This should be indistinguishable from a
* failed authentication.
*/
packet_start(SSH_SMSG_FAILURE);
packet_send();
packet_write_wait();
}
/* NOTREACHED */
abort();
}
/*
* read packets and try to authenticate local user *pw.
* return if authentication is successfull
*/
void
do_authloop(struct passwd * pw)
{
int attempt = 0;
unsigned int bits;
RSA *client_host_key;
BIGNUM *n;
char *client_user, *password;
char user[1024];
unsigned int dlen;
int plen, nlen, elen;
unsigned int ulen;
int type = 0;
void (*authlog) (const char *fmt,...) = verbose;
/* Indicate that authentication is needed. */
packet_start(SSH_SMSG_FAILURE);
packet_send();
packet_write_wait();
for (attempt = 1;; attempt++) {
int authenticated = 0;
strlcpy(user, "", sizeof user);
/* Get a packet from the client. */
type = packet_read(&plen);
/* Process the packet. */
switch (type) {
#ifdef AFS
case SSH_CMSG_HAVE_KERBEROS_TGT:
if (!options.kerberos_tgt_passing) {
/* packet_get_all(); */
verbose("Kerberos tgt passing disabled.");
break;
} else {
/* Accept Kerberos tgt. */
char *tgt = packet_get_string(&dlen);
packet_integrity_check(plen, 4 + dlen, type);
if (!auth_kerberos_tgt(pw, tgt))
verbose("Kerberos tgt REFUSED for %s", pw->pw_name);
xfree(tgt);
}
continue;
case SSH_CMSG_HAVE_AFS_TOKEN:
if (!options.afs_token_passing || !k_hasafs()) {
/* packet_get_all(); */
verbose("AFS token passing disabled.");
break;
} else {
/* Accept AFS token. */
char *token_string = packet_get_string(&dlen);
packet_integrity_check(plen, 4 + dlen, type);
if (!auth_afs_token(pw, token_string))
verbose("AFS token REFUSED for %s", pw->pw_name);
xfree(token_string);
}
continue;
#endif /* AFS */
#ifdef KRB4
case SSH_CMSG_AUTH_KERBEROS:
if (!options.kerberos_authentication) {
/* packet_get_all(); */
verbose("Kerberos authentication disabled.");
break;
} else {
/* Try Kerberos v4 authentication. */
KTEXT_ST auth;
char *tkt_user = NULL;
char *kdata = packet_get_string((unsigned int *) &auth.length);
packet_integrity_check(plen, 4 + auth.length, type);
if (auth.length < MAX_KTXT_LEN)
memcpy(auth.dat, kdata, auth.length);
xfree(kdata);
authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);
if (authenticated) {
snprintf(user, sizeof user, " tktuser %s", tkt_user);
xfree(tkt_user);
}
}
break;
#endif /* KRB4 */
case SSH_CMSG_AUTH_RHOSTS:
if (!options.rhosts_authentication) {
verbose("Rhosts authentication disabled.");
break;
}
/*
* Get client user name. Note that we just have to
* trust the client; this is one reason why rhosts
* authentication is insecure. (Another is
* IP-spoofing on a local network.)
*/
client_user = packet_get_string(&ulen);
packet_integrity_check(plen, 4 + ulen, type);
/* Try to authenticate using /etc/hosts.equiv and
.rhosts. */
authenticated = auth_rhosts(pw, client_user);
snprintf(user, sizeof user, " ruser %s", client_user);
xfree(client_user);
break;
case SSH_CMSG_AUTH_RHOSTS_RSA:
if (!options.rhosts_rsa_authentication) {
verbose("Rhosts with RSA authentication disabled.");
break;
}
/*
* Get client user name. Note that we just have to
* trust the client; root on the client machine can
* claim to be any user.
*/
client_user = packet_get_string(&ulen);
/* Get the client host key. */
client_host_key = RSA_new();
if (client_host_key == NULL)
fatal("RSA_new failed");
client_host_key->e = BN_new();
client_host_key->n = BN_new();
if (client_host_key->e == NULL || client_host_key->n == NULL)
fatal("BN_new failed");
bits = packet_get_int();
packet_get_bignum(client_host_key->e, &elen);
packet_get_bignum(client_host_key->n, &nlen);
if (bits != BN_num_bits(client_host_key->n))
log("Warning: keysize mismatch for client_host_key: "
"actual %d, announced %d", BN_num_bits(client_host_key->n), bits);
packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
authenticated = auth_rhosts_rsa(pw, client_user, client_host_key);
RSA_free(client_host_key);
snprintf(user, sizeof user, " ruser %s", client_user);
xfree(client_user);
break;
case SSH_CMSG_AUTH_RSA:
if (!options.rsa_authentication) {
verbose("RSA authentication disabled.");
break;
}
/* RSA authentication requested. */
n = BN_new();
packet_get_bignum(n, &nlen);
packet_integrity_check(plen, nlen, type);
authenticated = auth_rsa(pw, n);
BN_clear_free(n);
break;
case SSH_CMSG_AUTH_PASSWORD:
if (!options.password_authentication) {
verbose("Password authentication disabled.");
break;
}
/*
* Read user password. It is in plain text, but was
* transmitted over the encrypted channel so it is
* not visible to an outside observer.
*/
password = packet_get_string(&dlen);
packet_integrity_check(plen, 4 + dlen, type);
/* Try authentication with the password. */
authenticated = auth_password(pw, password);
memset(password, 0, strlen(password));
xfree(password);
break;
#ifdef SKEY
case SSH_CMSG_AUTH_TIS:
debug("rcvd SSH_CMSG_AUTH_TIS");
if (options.skey_authentication == 1) {
char *skeyinfo = skey_keyinfo(pw->pw_name);
if (skeyinfo == NULL) {
debug("generating fake skeyinfo for %.100s.", pw->pw_name);
skeyinfo = skey_fake_keyinfo(pw->pw_name);
}
if (skeyinfo != NULL) {
/* we send our s/key- in tis-challenge messages */
debug("sending challenge '%s'", skeyinfo);
packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
packet_put_string(skeyinfo, strlen(skeyinfo));
packet_send();
packet_write_wait();
continue;
}
}
break;
case SSH_CMSG_AUTH_TIS_RESPONSE:
debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
if (options.skey_authentication == 1) {
char *response = packet_get_string(&dlen);
debug("skey response == '%s'", response);
packet_integrity_check(plen, 4 + dlen, type);
authenticated = (skey_haskey(pw->pw_name) == 0 &&
skey_passcheck(pw->pw_name, response) != -1);
xfree(response);
}
break;
#else
case SSH_CMSG_AUTH_TIS:
/* TIS Authentication is unsupported */
log("TIS authentication unsupported.");
break;
#endif
default:
/*
* Any unknown messages will be ignored (and failure
* returned) during authentication.
*/
log("Unknown message during authentication: type %d", type);
break;
}
/*
* Check if the user is logging in as root and root logins
* are disallowed.
* Note that root login is allowed for forced commands.
*/
if (authenticated && pw->pw_uid == 0 && !options.permit_root_login) {
if (forced_command) {
log("Root login accepted for forced command.");
} else {
authenticated = 0;
log("ROOT LOGIN REFUSED FROM %.200s",
get_canonical_hostname());
}
}
/* Raise logging level */
if (authenticated ||
attempt == AUTH_FAIL_LOG ||
type == SSH_CMSG_AUTH_PASSWORD)
authlog = log;
authlog("%s %s for %.200s from %.200s port %d%s",
authenticated ? "Accepted" : "Failed",
get_authname(type),
pw->pw_uid == 0 ? "ROOT" : pw->pw_name,
get_remote_ipaddr(),
get_remote_port(),
user);
if (authenticated)
return;
if (attempt > AUTH_FAIL_MAX)
packet_disconnect(AUTH_FAIL_MSG, pw->pw_name);
/* Send a message indicating that the authentication attempt failed. */
packet_start(SSH_SMSG_FAILURE);
packet_send();
packet_write_wait();
}
}
/*
* Performs authentication of an incoming connection. Session key has already
* been exchanged and encryption is enabled.
*/
void
do_authentication()
{
struct passwd *pw, pwcopy;
int plen;
unsigned int ulen;
char *user;
/* Get the name of the user that we wish to log in as. */
packet_read_expect(&plen, SSH_CMSG_USER);
/* Get the user name. */
user = packet_get_string(&ulen);
packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
setproctitle("%s", user);
#ifdef AFS
/* If machine has AFS, set process authentication group. */
if (k_hasafs()) {
k_setpag();
k_unlog();
}
#endif /* AFS */
/* Verify that the user is a valid user. */
pw = getpwnam(user);
if (!pw || !allowed_user(pw))
do_fake_authloop1(user);
xfree(user);
/* Take a copy of the returned structure. */
memset(&pwcopy, 0, sizeof(pwcopy));
pwcopy.pw_name = xstrdup(pw->pw_name);
pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
pwcopy.pw_uid = pw->pw_uid;
pwcopy.pw_gid = pw->pw_gid;
pwcopy.pw_dir = xstrdup(pw->pw_dir);
pwcopy.pw_shell = xstrdup(pw->pw_shell);
pw = &pwcopy;
/*
* If we are not running as root, the user must have the same uid as
* the server.
*/
if (getuid() != 0 && pw->pw_uid != getuid())
packet_disconnect("Cannot change user when server not running as root.");
debug("Attempting authentication for %.100s.", pw->pw_name);
/* If the user has no password, accept authentication immediately. */
if (options.password_authentication &&
#ifdef KRB4
(!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
#endif /* KRB4 */
auth_password(pw, "")) {
/* Authentication with empty password succeeded. */
log("Login for user %s from %.100s, accepted without authentication.",
pw->pw_name, get_remote_ipaddr());
} else {
/* Loop until the user has been authenticated or the
connection is closed, do_authloop() returns only if
authentication is successfull */
do_authloop(pw);
}
/* The user has been authenticated and accepted. */
packet_start(SSH_SMSG_SUCCESS);
packet_send();
packet_write_wait();
/* Perform session preparation. */
do_authenticated(pw);
}

467
crypto/openssh/auth2.c Normal file
View File

@ -0,0 +1,467 @@
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Markus Friedl.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: auth2.c,v 1.8 2000/05/08 17:42:24 markus Exp $");
#include <openssl/dsa.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include "xmalloc.h"
#include "rsa.h"
#include "ssh.h"
#include "pty.h"
#include "packet.h"
#include "buffer.h"
#include "cipher.h"
#include "servconf.h"
#include "compat.h"
#include "channels.h"
#include "bufaux.h"
#include "ssh2.h"
#include "auth.h"
#include "session.h"
#include "dispatch.h"
#include "auth.h"
#include "key.h"
#include "kex.h"
#include "dsa.h"
#include "uidswap.h"
/* import */
extern ServerOptions options;
extern unsigned char *session_id2;
extern int session_id2_len;
/* protocol */
void input_service_request(int type, int plen);
void input_userauth_request(int type, int plen);
void protocol_error(int type, int plen);
/* auth */
int ssh2_auth_none(struct passwd *pw);
int ssh2_auth_password(struct passwd *pw);
int ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen);
/* helper */
struct passwd* auth_set_user(char *u, char *s);
int user_dsa_key_allowed(struct passwd *pw, Key *key);
typedef struct Authctxt Authctxt;
struct Authctxt {
char *user;
char *service;
struct passwd pw;
int valid;
};
static Authctxt *authctxt = NULL;
static int userauth_success = 0;
/*
* loop until userauth_success == TRUE
*/
void
do_authentication2()
{
/* turn off skey/kerberos, not supported by SSH2 */
#ifdef SKEY
options.skey_authentication = 0;
#endif
#ifdef KRB4
options.kerberos_authentication = 0;
#endif
dispatch_init(&protocol_error);
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
dispatch_run(DISPATCH_BLOCK, &userauth_success);
do_authenticated2();
}
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);
packet_done();
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 void (*authlog) (const char *fmt,...) = verbose;
static int attempt = 0;
unsigned int len, rlen;
int authenticated = 0;
char *raw, *user, *service, *method, *authmsg = NULL;
struct passwd *pw;
if (++attempt == AUTH_FAIL_MAX)
packet_disconnect("too many failed userauth_requests");
raw = packet_get_raw(&rlen);
if (plen != rlen)
fatal("plen != rlen");
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) {
authenticated = ssh2_auth_none(pw);
} else if (strcmp(method, "password") == 0) {
authenticated = ssh2_auth_password(pw);
} else if (strcmp(method, "publickey") == 0) {
authenticated = ssh2_auth_pubkey(pw, raw, rlen);
}
}
if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
authenticated = 0;
log("ROOT LOGIN REFUSED FROM %.200s",
get_canonical_hostname());
}
/* Raise logging level */
if (authenticated == 1 ||
attempt == AUTH_FAIL_LOG ||
strcmp(method, "password") == 0)
authlog = log;
/* Log before sending the reply */
if (authenticated == 1) {
authmsg = "Accepted";
} else if (authenticated == 0) {
authmsg = "Failed";
} else {
authmsg = "Postponed";
}
authlog("%s %s for %.200s from %.200s port %d ssh2",
authmsg,
method,
pw && pw->pw_uid == 0 ? "ROOT" : user,
get_remote_ipaddr(),
get_remote_port());
/* XXX todo: check if multiple auth methods are needed */
if (authenticated == 1) {
/* turn off userauth */
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
packet_start(SSH2_MSG_USERAUTH_SUCCESS);
packet_send();
packet_write_wait();
/* now we can break out */
userauth_success = 1;
} else if (authenticated == 0) {
packet_start(SSH2_MSG_USERAUTH_FAILURE);
packet_put_cstring("publickey,password"); /* XXX dynamic */
packet_put_char(0); /* XXX partial success, unused */
packet_send();
packet_write_wait();
}
xfree(service);
xfree(user);
xfree(method);
}
int
ssh2_auth_none(struct passwd *pw)
{
packet_done();
return auth_password(pw, "");
}
int
ssh2_auth_password(struct passwd *pw)
{
char *password;
int authenticated = 0;
int change;
unsigned int len;
change = packet_get_char();
if (change)
log("password change not supported");
password = packet_get_string(&len);
packet_done();
if (options.password_authentication &&
auth_password(pw, password) == 1)
authenticated = 1;
memset(password, 0, len);
xfree(password);
return authenticated;
}
int
ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen)
{
Buffer b;
Key *key;
char *pkalg, *pkblob, *sig;
unsigned int alen, blen, slen;
int have_sig;
int authenticated = 0;
if (options.dsa_authentication == 0) {
debug("pubkey auth disabled");
return 0;
}
if (datafellows & SSH_BUG_PUBKEYAUTH) {
log("bug compatibility with ssh-2.0.13 pubkey not implemented");
return 0;
}
have_sig = packet_get_char();
pkalg = packet_get_string(&alen);
if (strcmp(pkalg, KEX_DSS) != 0) {
xfree(pkalg);
log("bad pkalg %s", pkalg); /*XXX*/
return 0;
}
pkblob = packet_get_string(&blen);
key = dsa_key_from_blob(pkblob, blen);
if (key != NULL) {
if (have_sig) {
sig = packet_get_string(&slen);
packet_done();
buffer_init(&b);
buffer_append(&b, session_id2, session_id2_len);
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
if (slen + 4 > rlen)
fatal("bad rlen/slen");
buffer_append(&b, raw, rlen - slen - 4);
#ifdef DEBUG_DSS
buffer_dump(&b);
#endif
/* test for correct signature */
if (user_dsa_key_allowed(pw, key) &&
dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
authenticated = 1;
buffer_clear(&b);
xfree(sig);
} else {
packet_done();
debug("test key...");
/* test whether pkalg/pkblob are acceptable */
/* XXX fake reply and always send PK_OK ? */
/*
* XXX this allows testing whether a user is allowed
* to login: if you happen to have a valid pubkey this
* message is sent. the message is NEVER sent at all
* if a user is not allowed to login. is this an
* issue? -markus
*/
if (user_dsa_key_allowed(pw, key)) {
packet_start(SSH2_MSG_USERAUTH_PK_OK);
packet_put_string(pkalg, alen);
packet_put_string(pkblob, blen);
packet_send();
packet_write_wait();
authenticated = -1;
}
}
key_free(key);
}
xfree(pkalg);
xfree(pkblob);
return authenticated;
}
/* set and get current user */
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: illegal user %s", u);
return NULL;
}
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();
}
/* return 1 if user allows given key */
int
user_dsa_key_allowed(struct passwd *pw, Key *key)
{
char line[8192], file[1024];
int found_key = 0;
unsigned int bits = -1;
FILE *f;
unsigned long linenum = 0;
struct stat st;
Key *found;
/* Temporarily use the user's uid. */
temporarily_use_uid(pw->pw_uid);
/* The authorized keys. */
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
SSH_USER_PERMITTED_KEYS2);
/* Fail quietly if file does not exist */
if (stat(file, &st) < 0) {
/* Restore the privileged uid. */
restore_uid();
return 0;
}
/* Open the file containing the authorized keys. */
f = fopen(file, "r");
if (!f) {
/* Restore the privileged uid. */
restore_uid();
return 0;
}
if (options.strict_modes) {
int fail = 0;
char buf[1024];
/* Check open file in order to avoid open/stat races */
if (fstat(fileno(f), &st) < 0 ||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0) {
snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: "
"bad ownership or modes for '%s'.", pw->pw_name, file);
fail = 1;
} else {
/* Check path to SSH_USER_PERMITTED_KEYS */
int i;
static const char *check[] = {
"", SSH_USER_DIR, NULL
};
for (i = 0; check[i]; i++) {
snprintf(line, sizeof line, "%.500s/%.100s",
pw->pw_dir, check[i]);
if (stat(line, &st) < 0 ||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0) {
snprintf(buf, sizeof buf,
"DSA authentication refused for %.100s: "
"bad ownership or modes for '%s'.",
pw->pw_name, line);
fail = 1;
break;
}
}
}
if (fail) {
log(buf);
fclose(f);
restore_uid();
return 0;
}
}
found_key = 0;
found = key_new(KEY_DSA);
while (fgets(line, sizeof(line), f)) {
char *cp;
linenum++;
/* Skip leading whitespace, empty and comment lines. */
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
;
if (!*cp || *cp == '\n' || *cp == '#')
continue;
bits = key_read(found, &cp);
if (bits == 0)
continue;
if (key_equal(found, key)) {
found_key = 1;
debug("matching key found: file %s, line %ld",
file, linenum);
break;
}
}
restore_uid();
fclose(f);
key_free(found);
return found_key;
}

View File

@ -1,19 +1,19 @@
/*
*
*
* authfd.h
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Wed Mar 29 01:17:41 1995 ylo
*
*
* Functions to interface with the SSH_AUTHENTICATION_FD socket.
*
*
*/
/* RCSID("$Id: authfd.h,v 1.6 1999/11/24 19:53:44 markus Exp $"); */
/* RCSID("$Id: authfd.h,v 1.7 2000/04/14 10:30:30 markus Exp $"); */
#ifndef AUTHFD_H
#define AUTHFD_H
@ -67,7 +67,7 @@ void ssh_close_authentication_connection(AuthenticationConnection * ac);
* integers before the call, and free the comment after a successful call
* (before calling ssh_get_next_identity).
*/
int
int
ssh_get_first_identity(AuthenticationConnection * connection,
BIGNUM * e, BIGNUM * n, char **comment);
@ -77,13 +77,13 @@ ssh_get_first_identity(AuthenticationConnection * connection,
* function. This returns 0 if there are no more identities. The caller
* must free comment after a successful return.
*/
int
int
ssh_get_next_identity(AuthenticationConnection * connection,
BIGNUM * e, BIGNUM * n, char **comment);
/* Requests the agent to decrypt the given challenge. Returns true if
the agent claims it was able to decrypt it. */
int
int
ssh_decrypt_challenge(AuthenticationConnection * auth,
BIGNUM * e, BIGNUM * n, BIGNUM * challenge,
unsigned char session_id[16],
@ -95,7 +95,7 @@ ssh_decrypt_challenge(AuthenticationConnection * auth,
* be used by normal applications. This returns true if the identity was
* successfully added.
*/
int
int
ssh_add_identity(AuthenticationConnection * connection, RSA * key,
const char *comment);

36
crypto/openssh/authfile.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef AUTHFILE_H
#define AUTHFILE_H
/*
* Saves the authentication (private) key in a file, encrypting it with
* passphrase.
* For RSA keys: The identification of the file (lowest 64 bits of n)
* will precede the key to provide identification of the key without
* needing a passphrase.
*/
int
save_private_key(const char *filename, const char *passphrase,
Key * private_key, const char *comment);
/*
* Loads the public part of the key file (public key and comment). Returns 0
* if an error occurred; zero if the public key was successfully read. The
* comment of the key is returned in comment_return if it is non-NULL; the
* caller must free the value with xfree.
*/
int
load_public_key(const char *filename, Key * pub,
char **comment_return);
/*
* Loads the private key from the file. Returns 0 if an error is encountered
* (file does not exist or is not readable, or passphrase is bad). This
* initializes the private key. The comment of the key is returned in
* comment_return if it is non-NULL; the caller must free the value with
* xfree.
*/
int
load_private_key(const char *filename, const char *passphrase,
Key * private_key, char **comment_return);
#endif

View File

@ -1,17 +1,17 @@
/*
*
*
* bufaux.h
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Wed Mar 29 02:18:23 1995 ylo
*
*
*/
/* RCSID("$Id: bufaux.h,v 1.4 1999/11/24 19:53:44 markus Exp $"); */
/* RCSID("$Id: bufaux.h,v 1.6 2000/04/14 10:30:30 markus Exp $"); */
#ifndef BUFAUX_H
#define BUFAUX_H
@ -23,9 +23,11 @@
* by (bits+7)/8 bytes of binary data, msb first.
*/
void buffer_put_bignum(Buffer * buffer, BIGNUM * value);
void buffer_put_bignum2(Buffer * buffer, BIGNUM * value);
/* Retrieves an BIGNUM from the buffer. */
int buffer_get_bignum(Buffer * buffer, BIGNUM * value);
int buffer_get_bignum2(Buffer *buffer, BIGNUM * value);
/* Returns an integer from the buffer (4 bytes, msb first). */
unsigned int buffer_get_int(Buffer * buffer);
@ -51,5 +53,6 @@ char *buffer_get_string(Buffer * buffer, unsigned int *length_ptr);
/* Stores and arbitrary binary string in the buffer. */
void buffer_put_string(Buffer * buffer, const void *buf, unsigned int len);
void buffer_put_cstring(Buffer *buffer, const char *s);
#endif /* BUFAUX_H */

View File

@ -1,20 +1,20 @@
/*
*
*
* buffer.c
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Sat Mar 18 04:15:33 1995 ylo
*
*
* Functions for manipulating fifo buffers (that can grow if needed).
*
*
*/
#include "includes.h"
RCSID("$Id: buffer.c,v 1.4 1999/11/24 19:53:44 markus Exp $");
RCSID("$Id: buffer.c,v 1.6 2000/04/14 10:30:30 markus Exp $");
#include "xmalloc.h"
#include "buffer.h"
@ -22,7 +22,7 @@ RCSID("$Id: buffer.c,v 1.4 1999/11/24 19:53:44 markus Exp $");
/* Initializes the buffer structure. */
void
void
buffer_init(Buffer *buffer)
{
buffer->alloc = 4096;
@ -33,7 +33,7 @@ buffer_init(Buffer *buffer)
/* Frees any memory used for the buffer. */
void
void
buffer_free(Buffer *buffer)
{
memset(buffer->buf, 0, buffer->alloc);
@ -45,7 +45,7 @@ buffer_free(Buffer *buffer)
* zero the memory.
*/
void
void
buffer_clear(Buffer *buffer)
{
buffer->offset = 0;
@ -54,7 +54,7 @@ buffer_clear(Buffer *buffer)
/* Appends data to the buffer, expanding it if necessary. */
void
void
buffer_append(Buffer *buffer, const char *data, unsigned int len)
{
char *cp;
@ -68,7 +68,7 @@ buffer_append(Buffer *buffer, const char *data, unsigned int len)
* to the allocated region.
*/
void
void
buffer_append_space(Buffer *buffer, char **datap, unsigned int len)
{
/* If the buffer is empty, start using it from the beginning. */
@ -102,7 +102,7 @@ buffer_append_space(Buffer *buffer, char **datap, unsigned int len)
/* Returns the number of bytes of data in the buffer. */
unsigned int
unsigned int
buffer_len(Buffer *buffer)
{
return buffer->end - buffer->offset;
@ -110,32 +110,32 @@ buffer_len(Buffer *buffer)
/* Gets data from the beginning of the buffer. */
void
void
buffer_get(Buffer *buffer, char *buf, unsigned int len)
{
if (len > buffer->end - buffer->offset)
fatal("buffer_get trying to get more bytes than in buffer");
fatal("buffer_get: trying to get more bytes than in buffer");
memcpy(buf, buffer->buf + buffer->offset, len);
buffer->offset += len;
}
/* Consumes the given number of bytes from the beginning of the buffer. */
void
void
buffer_consume(Buffer *buffer, unsigned int bytes)
{
if (bytes > buffer->end - buffer->offset)
fatal("buffer_get trying to get more bytes than in buffer");
fatal("buffer_consume: trying to get more bytes than in buffer");
buffer->offset += bytes;
}
/* Consumes the given number of bytes from the end of the buffer. */
void
void
buffer_consume_end(Buffer *buffer, unsigned int bytes)
{
if (bytes > buffer->end - buffer->offset)
fatal("buffer_get trying to get more bytes than in buffer");
fatal("buffer_consume_end: trying to get more bytes than in buffer");
buffer->end -= bytes;
}
@ -149,7 +149,7 @@ buffer_ptr(Buffer *buffer)
/* Dumps the contents of the buffer to stderr. */
void
void
buffer_dump(Buffer *buffer)
{
int i;

View File

@ -1,19 +1,19 @@
/*
*
*
* buffer.h
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Sat Mar 18 04:12:25 1995 ylo
*
*
* Code for manipulating FIFO buffers.
*
*
*/
/* RCSID("$Id: buffer.h,v 1.3 1999/11/24 19:53:44 markus Exp $"); */
/* RCSID("$Id: buffer.h,v 1.4 2000/04/14 10:30:30 markus Exp $"); */
#ifndef BUFFER_H
#define BUFFER_H

View File

@ -1,20 +1,20 @@
/*
*
*
* canohost.c
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Sun Jul 2 17:52:22 1995 ylo
*
*
* Functions for returning the canonical host name of the remote site.
*
*
*/
#include "includes.h"
RCSID("$Id: canohost.c,v 1.11 2000/01/04 13:41:32 markus Exp $");
RCSID("$Id: canohost.c,v 1.12 2000/04/14 10:30:30 markus Exp $");
#include "packet.h"
#include "xmalloc.h"
@ -241,7 +241,7 @@ get_sock_port(int sock, int local)
/* Returns remote/local port number for the current connection. */
int
int
get_port(int local)
{
/*
@ -255,13 +255,13 @@ get_port(int local)
return get_sock_port(packet_get_connection_in(), local);
}
int
int
get_peer_port(int sock)
{
return get_sock_port(sock, 0);
}
int
int
get_remote_port()
{
return get_port(0);

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* RCSID("$Id: channels.h,v 1.6 1999/11/24 19:53:45 markus Exp $"); */
/* RCSID("$Id: channels.h,v 1.12 2000/05/03 18:03:06 markus Exp $"); */
#ifndef CHANNELS_H
#define CHANNELS_H
@ -10,17 +10,18 @@
#define SSH_CHANNEL_OPENING 3 /* waiting for confirmation */
#define SSH_CHANNEL_OPEN 4 /* normal open two-way channel */
#define SSH_CHANNEL_CLOSED 5 /* waiting for close confirmation */
/* SSH_CHANNEL_AUTH_FD 6 authentication fd */
#define SSH_CHANNEL_AUTH_SOCKET 7 /* authentication socket */
/* SSH_CHANNEL_AUTH_SOCKET_FD 8 connection to auth socket */
#define SSH_CHANNEL_X11_OPEN 9 /* reading first X11 packet */
#define SSH_CHANNEL_INPUT_DRAINING 10 /* sending remaining data to conn */
#define SSH_CHANNEL_OUTPUT_DRAINING 11 /* sending remaining data to app */
#define SSH_CHANNEL_AUTH_SOCKET 6 /* authentication socket */
#define SSH_CHANNEL_X11_OPEN 7 /* reading first X11 packet */
#define SSH_CHANNEL_INPUT_DRAINING 8 /* sending remaining data to conn */
#define SSH_CHANNEL_OUTPUT_DRAINING 9 /* sending remaining data to app */
#define SSH_CHANNEL_LARVAL 10 /* larval session */
#define SSH_CHANNEL_MAX_TYPE 11
/*
* Data structure for channel data. This is iniailized in channel_allocate
* and cleared in channel_free.
*/
typedef void channel_callback_fn(int id, void *arg);
typedef struct Channel {
int type; /* channel type/state */
@ -29,15 +30,208 @@ typedef struct Channel {
/* peer can be reached over encrypted connection, via packet-sent */
int istate; /* input from channel (state of receive half) */
int ostate; /* output to channel (state of transmit half) */
int sock; /* data socket, linked to this channel */
int flags; /* close sent/rcvd */
int rfd; /* read fd */
int wfd; /* write fd */
int efd; /* extended fd */
int sock; /* sock fd */
Buffer input; /* data read from socket, to be sent over
* encrypted connection */
Buffer output; /* data received over encrypted connection for
* send on socket */
Buffer extended;
char path[200]; /* path for unix domain sockets, or host name
* for forwards */
int listening_port; /* port being listened for forwards */
int host_port; /* remote port to connect for forwards */
char *remote_name; /* remote hostname */
int remote_window;
int remote_maxpacket;
int local_window;
int local_window_max;
int local_consumed;
int local_maxpacket;
int extended_usage;
char *ctype; /* type */
/* callback */
channel_callback_fn *cb_fn;
void *cb_arg;
int cb_event;
channel_callback_fn *dettach_user;
} Channel;
#define CHAN_EXTENDED_IGNORE 0
#define CHAN_EXTENDED_READ 1
#define CHAN_EXTENDED_WRITE 2
void channel_set_fds(int id, int rfd, int wfd, int efd, int extusage);
void channel_open(int id);
void channel_request(int id, char *service, int wantconfirm);
void channel_request_start(int id, char *service, int wantconfirm);
void channel_register_callback(int id, int mtype, channel_callback_fn *fn, void *arg);
void channel_register_cleanup(int id, channel_callback_fn *fn);
void channel_cancel_cleanup(int id);
Channel *channel_lookup(int id);
int
channel_new(char *ctype, int type, int rfd, int wfd, int efd,
int window, int maxpack, int extended_usage, char *remote_name);
void channel_input_channel_request(int type, int plen);
void channel_input_close(int type, int plen);
void channel_input_close_confirmation(int type, int plen);
void channel_input_data(int type, int plen);
void channel_input_extended_data(int type, int plen);
void channel_input_ieof(int type, int plen);
void channel_input_oclose(int type, int plen);
void channel_input_open_confirmation(int type, int plen);
void channel_input_open_failure(int type, int plen);
void channel_input_port_open(int type, int plen);
void channel_input_window_adjust(int type, int plen);
void channel_input_open(int type, int plen);
/* Sets specific protocol options. */
void channel_set_options(int hostname_in_open);
/*
* Allocate a new channel object and set its type and socket. Remote_name
* must have been allocated with xmalloc; this will free it when the channel
* is freed.
*/
int channel_allocate(int type, int sock, char *remote_name);
/* Free the channel and close its socket. */
void channel_free(int channel);
/* Add any bits relevant to channels in select bitmasks. */
void channel_prepare_select(fd_set * readset, fd_set * writeset);
/*
* After select, perform any appropriate operations for channels which have
* events pending.
*/
void channel_after_select(fd_set * readset, fd_set * writeset);
/* If there is data to send to the connection, send some of it now. */
void channel_output_poll(void);
/* Returns true if no channel has too much buffered data. */
int channel_not_very_much_buffered_data(void);
/* This closes any sockets that are listening for connections; this removes
any unix domain sockets. */
void channel_stop_listening(void);
/*
* Closes the sockets of all channels. This is used to close extra file
* descriptors after a fork.
*/
void channel_close_all(void);
/* Returns the maximum file descriptor number used by the channels. */
int channel_max_fd(void);
/* Returns true if there is still an open channel over the connection. */
int channel_still_open(void);
/*
* Returns a string containing a list of all open channels. The list is
* suitable for displaying to the user. It uses crlf instead of newlines.
* The caller should free the string with xfree.
*/
char *channel_open_message(void);
/*
* Initiate forwarding of connections to local port "port" through the secure
* channel to host:port from remote side. This never returns if there was an
* error.
*/
void
channel_request_local_forwarding(u_short port, const char *host,
u_short remote_port, int gateway_ports);
/*
* Initiate forwarding of connections to port "port" on remote host through
* the secure channel to host:port from local side. This never returns if
* there was an error. This registers that open requests for that port are
* permitted.
*/
void
channel_request_remote_forwarding(u_short port, const char *host,
u_short remote_port);
/*
* Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually
* called by the server, because the user could connect to any port anyway,
* and the server has no way to know but to trust the client anyway.
*/
void channel_permit_all_opens(void);
/*
* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
* listening for the port, and sends back a success reply (or disconnect
* message if there was an error). This never returns if there was an error.
*/
void channel_input_port_forward_request(int is_root, int gateway_ports);
/*
* Creates a port for X11 connections, and starts listening for it. Returns
* the display name, or NULL if an error was encountered.
*/
char *x11_create_display(int screen);
/*
* Creates an internet domain socket for listening for X11 connections.
* Returns a suitable value for the DISPLAY variable, or NULL if an error
* occurs.
*/
char *x11_create_display_inet(int screen, int x11_display_offset);
/*
* This is called when SSH_SMSG_X11_OPEN is received. The packet contains
* the remote channel number. We should do whatever we want, and respond
* with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.
*/
void x11_input_open(int type, int plen);
/*
* Requests forwarding of X11 connections. This should be called on the
* client only.
*/
void x11_request_forwarding(void);
/*
* Requests forwarding for X11 connections, with authentication spoofing.
* This should be called in the client only.
*/
void
x11_request_forwarding_with_spoofing(int client_session_id,
const char *proto, const char *data);
/* Sends a message to the server to request authentication fd forwarding. */
void auth_request_forwarding(void);
/*
* Returns the name of the forwarded authentication socket. Returns NULL if
* there is no forwarded authentication socket. The returned value points to
* a static buffer.
*/
char *auth_get_socket_name(void);
/*
* This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.
* This starts forwarding authentication requests.
*/
void auth_input_request_forwarding(struct passwd * pw);
/* This is called to process an SSH_SMSG_AGENT_OPEN message. */
void auth_input_open_request(int type, int plen);
/* XXX */
int channel_connect_to(const char *host, u_short host_port);
int x11_connect_display(void);
#endif

View File

@ -1,21 +1,22 @@
/*
*
*
* clientloop.c
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
*
*
* Created: Sat Sep 23 12:23:57 1995 ylo
*
*
* The main loop for the interactive session (client side).
*
*
* SSH2 support added by Markus Friedl.
*/
#include "includes.h"
RCSID("$Id: clientloop.c,v 1.14 1999/12/06 20:15:26 deraadt Exp $");
RCSID("$Id: clientloop.c,v 1.26 2000/05/08 17:42:24 markus Exp $");
#include "xmalloc.h"
#include "ssh.h"
@ -24,6 +25,12 @@ RCSID("$Id: clientloop.c,v 1.14 1999/12/06 20:15:26 deraadt Exp $");
#include "authfd.h"
#include "readconf.h"
#include "ssh2.h"
#include "compat.h"
#include "channels.h"
#include "dispatch.h"
/* Flag indicating that stdin should be redirected from /dev/null. */
extern int stdin_null_flag;
@ -70,9 +77,13 @@ static unsigned long stdin_bytes, stdout_bytes, stderr_bytes;
static int quit_pending; /* Set to non-zero to quit the client loop. */
static int escape_char; /* Escape character. */
void client_init_dispatch(void);
int session_ident = -1;
/* Returns the user\'s terminal to normal mode if it had been put in raw mode. */
void
void
leave_raw_mode()
{
if (!in_raw_mode)
@ -86,7 +97,7 @@ leave_raw_mode()
/* Puts the user\'s terminal in raw mode. */
void
void
enter_raw_mode()
{
struct termios tio;
@ -112,7 +123,7 @@ enter_raw_mode()
/* Restores stdin to blocking mode. */
void
void
leave_non_blocking()
{
if (in_non_blocking_mode) {
@ -124,7 +135,7 @@ leave_non_blocking()
/* Puts stdin terminal in non-blocking mode. */
void
void
enter_non_blocking()
{
in_non_blocking_mode = 1;
@ -137,7 +148,7 @@ enter_non_blocking()
* flag indicating that the window has changed.
*/
void
void
window_change_handler(int sig)
{
received_window_change_signal = 1;
@ -149,7 +160,7 @@ window_change_handler(int sig)
* signals must be trapped to restore terminal modes.
*/
void
void
signal_handler(int sig)
{
if (in_raw_mode)
@ -166,7 +177,7 @@ signal_handler(int sig)
* available resolution.
*/
double
double
get_current_time()
{
struct timeval tv;
@ -180,7 +191,7 @@ get_current_time()
* not appear to wake up when redirecting from /dev/null.
*/
void
void
client_check_initial_eof_on_stdin()
{
int len;
@ -228,115 +239,13 @@ client_check_initial_eof_on_stdin()
}
}
/*
* Get packets from the connection input buffer, and process them as long as
* there are packets available.
*/
void
client_process_buffered_input_packets()
{
int type;
char *data;
unsigned int data_len;
int payload_len;
/* Process any buffered packets from the server. */
while (!quit_pending &&
(type = packet_read_poll(&payload_len)) != SSH_MSG_NONE) {
switch (type) {
case SSH_SMSG_STDOUT_DATA:
data = packet_get_string(&data_len);
packet_integrity_check(payload_len, 4 + data_len, type);
buffer_append(&stdout_buffer, data, data_len);
stdout_bytes += data_len;
memset(data, 0, data_len);
xfree(data);
break;
case SSH_SMSG_STDERR_DATA:
data = packet_get_string(&data_len);
packet_integrity_check(payload_len, 4 + data_len, type);
buffer_append(&stderr_buffer, data, data_len);
stdout_bytes += data_len;
memset(data, 0, data_len);
xfree(data);
break;
case SSH_SMSG_EXITSTATUS:
packet_integrity_check(payload_len, 4, type);
exit_status = packet_get_int();
/* Acknowledge the exit. */
packet_start(SSH_CMSG_EXIT_CONFIRMATION);
packet_send();
/*
* Must wait for packet to be sent since we are
* exiting the loop.
*/
packet_write_wait();
/* Flag that we want to exit. */
quit_pending = 1;
break;
case SSH_SMSG_X11_OPEN:
x11_input_open(payload_len);
break;
case SSH_MSG_PORT_OPEN:
channel_input_port_open(payload_len);
break;
case SSH_SMSG_AGENT_OPEN:
packet_integrity_check(payload_len, 4, type);
auth_input_open_request();
break;
case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
packet_integrity_check(payload_len, 4 + 4, type);
channel_input_open_confirmation();
break;
case SSH_MSG_CHANNEL_OPEN_FAILURE:
packet_integrity_check(payload_len, 4, type);
channel_input_open_failure();
break;
case SSH_MSG_CHANNEL_DATA:
channel_input_data(payload_len);
break;
case SSH_MSG_CHANNEL_CLOSE:
packet_integrity_check(payload_len, 4, type);
channel_input_close();
break;
case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION:
packet_integrity_check(payload_len, 4, type);
channel_input_close_confirmation();
break;
default:
/*
* Any unknown packets received during the actual
* session cause the session to terminate. This is
* intended to make debugging easier since no
* confirmations are sent. Any compatible protocol
* extensions must be negotiated during the
* preparatory phase.
*/
packet_disconnect("Protocol error during session: type %d",
type);
}
}
}
/*
* Make packets from buffered stdin data, and buffer them for sending to the
* connection.
*/
void
void
client_make_packets_from_stdin_data()
{
unsigned int len;
@ -367,26 +276,35 @@ client_make_packets_from_stdin_data()
* appropriate.
*/
void
void
client_check_window_change()
{
/* Send possible window change message to the server. */
if (received_window_change_signal) {
struct winsize ws;
struct winsize ws;
/* Clear the window change indicator. */
received_window_change_signal = 0;
if (! received_window_change_signal)
return;
/** XXX race */
received_window_change_signal = 0;
/* Read new window size. */
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) >= 0) {
/* Successful, send the packet now. */
packet_start(SSH_CMSG_WINDOW_SIZE);
packet_put_int(ws.ws_row);
packet_put_int(ws.ws_col);
packet_put_int(ws.ws_xpixel);
packet_put_int(ws.ws_ypixel);
packet_send();
}
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
return;
debug("client_check_window_change: changed");
if (compat20) {
channel_request_start(session_ident, "window-change", 0);
packet_put_int(ws.ws_col);
packet_put_int(ws.ws_row);
packet_put_int(ws.ws_xpixel);
packet_put_int(ws.ws_ypixel);
packet_send();
} else {
packet_start(SSH_CMSG_WINDOW_SIZE);
packet_put_int(ws.ws_row);
packet_put_int(ws.ws_col);
packet_put_int(ws.ws_xpixel);
packet_put_int(ws.ws_ypixel);
packet_send();
}
}
@ -395,27 +313,37 @@ client_check_window_change()
* one of the file descriptors).
*/
void
void
client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
{
/*debug("client_wait_until_can_do_something"); */
/* Initialize select masks. */
FD_ZERO(readset);
/* Read from the connection, unless our buffers are full. */
if (buffer_len(&stdout_buffer) < buffer_high &&
buffer_len(&stderr_buffer) < buffer_high &&
channel_not_very_much_buffered_data())
FD_SET(connection_in, readset);
/*
* Read from stdin, unless we have seen EOF or have very much
* buffered data to send to the server.
*/
if (!stdin_eof && packet_not_very_much_data_to_write())
FD_SET(fileno(stdin), readset);
FD_ZERO(writeset);
if (!compat20) {
/* Read from the connection, unless our buffers are full. */
if (buffer_len(&stdout_buffer) < buffer_high &&
buffer_len(&stderr_buffer) < buffer_high &&
channel_not_very_much_buffered_data())
FD_SET(connection_in, readset);
/*
* Read from stdin, unless we have seen EOF or have very much
* buffered data to send to the server.
*/
if (!stdin_eof && packet_not_very_much_data_to_write())
FD_SET(fileno(stdin), readset);
/* Select stdout/stderr if have data in buffer. */
if (buffer_len(&stdout_buffer) > 0)
FD_SET(fileno(stdout), writeset);
if (buffer_len(&stderr_buffer) > 0)
FD_SET(fileno(stderr), writeset);
} else {
FD_SET(connection_in, readset);
}
/* Add any selections by the channel mechanism. */
channel_prepare_select(readset, writeset);
@ -423,14 +351,7 @@ client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
if (packet_have_data_to_write())
FD_SET(connection_out, writeset);
/* Select stdout if have data in buffer. */
if (buffer_len(&stdout_buffer) > 0)
FD_SET(fileno(stdout), writeset);
/* Select stderr if have data in buffer. */
if (buffer_len(&stderr_buffer) > 0)
FD_SET(fileno(stderr), writeset);
/* move UP XXX */
/* Update maximum file descriptor number, if appropriate. */
if (channel_max_fd() > max_fd)
max_fd = channel_max_fd();
@ -459,7 +380,7 @@ client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
}
}
void
void
client_suspend_self()
{
struct winsize oldws, newws;
@ -504,11 +425,11 @@ client_suspend_self()
enter_raw_mode();
}
void
client_process_input(fd_set * readset)
void
client_process_net_input(fd_set * readset)
{
int len, pid;
char buf[8192], *s;
int len;
char buf[8192];
/*
* Read input from the server, and add any such data to the buffer of
@ -517,6 +438,7 @@ client_process_input(fd_set * readset)
if (FD_ISSET(connection_in, readset)) {
/* Read as much as possible. */
len = read(connection_in, buf, sizeof(buf));
/*debug("read connection_in len %d", len); XXX */
if (len == 0) {
/* Received EOF. The remote host has closed the connection. */
snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n",
@ -544,6 +466,15 @@ client_process_input(fd_set * readset)
}
packet_process_incoming(buf, len);
}
}
void
client_process_input(fd_set * readset)
{
int len;
pid_t pid;
char buf[8192], *s;
/* Read input from stdin. */
if (FD_ISSET(fileno(stdin), readset)) {
/* Read as much as possible. */
@ -727,7 +658,7 @@ Supported escape sequences:\r\n\
}
}
void
void
client_process_output(fd_set * writeset)
{
int len;
@ -775,6 +706,24 @@ client_process_output(fd_set * writeset)
}
}
/*
* Get packets from the connection input buffer, and process them as long as
* there are packets available.
*
* Any unknown packets received during the actual
* session cause the session to terminate. This is
* intended to make debugging easier since no
* confirmations are sent. Any compatible protocol
* extensions must be negotiated during the
* preparatory phase.
*/
void
client_process_buffered_input_packets()
{
dispatch_run(DISPATCH_NONBLOCK, &quit_pending);
}
/*
* Implements the interactive session with the server. This is called after
* the user has been authenticated, and a command has been started on the
@ -782,7 +731,7 @@ client_process_output(fd_set * writeset)
* character for terminating or suspending the session.
*/
int
int
client_loop(int have_pty, int escape_char_arg)
{
extern Options options;
@ -816,6 +765,8 @@ client_loop(int have_pty, int escape_char_arg)
buffer_init(&stdout_buffer);
buffer_init(&stderr_buffer);
client_init_dispatch();
/* Set signal handlers to restore non-blocking mode. */
signal(SIGINT, signal_handler);
signal(SIGQUIT, signal_handler);
@ -828,7 +779,8 @@ client_loop(int have_pty, int escape_char_arg)
enter_raw_mode();
/* Check if we should immediately send of on stdin. */
client_check_initial_eof_on_stdin();
if (!compat20)
client_check_initial_eof_on_stdin();
/* Main loop of the client for the interactive session mode. */
while (!quit_pending) {
@ -837,11 +789,17 @@ client_loop(int have_pty, int escape_char_arg)
/* Process buffered packets sent by the server. */
client_process_buffered_input_packets();
if (compat20 && !channel_still_open()) {
debug("!channel_still_open.");
break;
}
/*
* Make packets of buffered stdin data, and buffer them for
* sending to the server.
*/
client_make_packets_from_stdin_data();
if (!compat20)
client_make_packets_from_stdin_data();
/*
* Make packets from buffered channel data, and buffer them
@ -871,17 +829,21 @@ client_loop(int have_pty, int escape_char_arg)
/* Do channel operations. */
channel_after_select(&readset, &writeset);
/*
* Process input from the connection and from stdin. Buffer
* any data that is available.
*/
client_process_input(&readset);
/* Buffer input from the connection. */
client_process_net_input(&readset);
/*
* Process output to stdout and stderr. Output to the
* connection is processed elsewhere (above).
*/
client_process_output(&writeset);
if (quit_pending)
break;
if (!compat20) {
/* Buffer data from stdin */
client_process_input(&readset);
/*
* Process output to stdout and stderr. Output to
* the connection is processed elsewhere (above).
*/
client_process_output(&writeset);
}
/* Send as much buffered packet data as possible to the sender. */
if (FD_ISSET(connection_out, &writeset))
@ -950,3 +912,206 @@ client_loop(int have_pty, int escape_char_arg)
debug("Exit status %d", exit_status);
return exit_status;
}
/*********/
void
client_input_stdout_data(int type, int plen)
{
unsigned int data_len;
char *data = packet_get_string(&data_len);
packet_integrity_check(plen, 4 + data_len, type);
buffer_append(&stdout_buffer, data, data_len);
stdout_bytes += data_len;
memset(data, 0, data_len);
xfree(data);
}
void
client_input_stderr_data(int type, int plen)
{
unsigned int data_len;
char *data = packet_get_string(&data_len);
packet_integrity_check(plen, 4 + data_len, type);
buffer_append(&stderr_buffer, data, data_len);
stdout_bytes += data_len;
memset(data, 0, data_len);
xfree(data);
}
void
client_input_exit_status(int type, int plen)
{
packet_integrity_check(plen, 4, type);
exit_status = packet_get_int();
/* Acknowledge the exit. */
packet_start(SSH_CMSG_EXIT_CONFIRMATION);
packet_send();
/*
* Must wait for packet to be sent since we are
* exiting the loop.
*/
packet_write_wait();
/* Flag that we want to exit. */
quit_pending = 1;
}
/* XXXX move to generic input handler */
void
client_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();
debug("client_input_channel_open: ctype %s rchan %d win %d max %d",
ctype, rchan, rwindow, rmaxpack);
if (strcmp(ctype, "x11") == 0) {
int sock;
char *originator;
int originator_port;
originator = packet_get_string(NULL);
if (datafellows & SSH_BUG_X11FWD) {
debug("buggy server: x11 request w/o originator_port");
originator_port = 0;
} else {
originator_port = packet_get_int();
}
packet_done();
/* XXX check permission */
xfree(originator);
/* XXX move to channels.c */
sock = x11_connect_display();
if (sock >= 0) {
id = channel_new("x11", SSH_CHANNEL_X11_OPEN,
sock, sock, -1, 4*1024, 32*1024, 0,
xstrdup("x11"));
c = channel_lookup(id);
}
}
/* XXX duplicate : */
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
client_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, &client_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
client_init_dispatch_13()
{
dispatch_init(NULL);
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close);
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation);
dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data);
dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
dispatch_set(SSH_SMSG_AGENT_OPEN, &auth_input_open_request);
dispatch_set(SSH_SMSG_EXITSTATUS, &client_input_exit_status);
dispatch_set(SSH_SMSG_STDERR_DATA, &client_input_stderr_data);
dispatch_set(SSH_SMSG_STDOUT_DATA, &client_input_stdout_data);
dispatch_set(SSH_SMSG_X11_OPEN, &x11_input_open);
}
void
client_init_dispatch_15()
{
client_init_dispatch_13();
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof);
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose);
}
void
client_init_dispatch()
{
if (compat20)
client_init_dispatch_20();
else if (compat13)
client_init_dispatch_13();
else
client_init_dispatch_15();
}
void
client_input_channel_req(int id, void *arg)
{
Channel *c = NULL;
unsigned int len;
int success = 0;
int reply;
char *rtype;
rtype = packet_get_string(&len);
reply = packet_get_char();
debug("client_input_channel_req: rtype %s reply %d", rtype, reply);
c = channel_lookup(id);
if (c == NULL)
fatal("session_input_channel_req: channel %d: bad channel", id);
if (session_ident == -1) {
error("client_input_channel_req: no channel %d", id);
} else if (id != session_ident) {
error("client_input_channel_req: bad channel %d != %d",
id, session_ident);
} else if (strcmp(rtype, "exit-status") == 0) {
success = 1;
exit_status = packet_get_int();
packet_done();
}
if (reply) {
packet_start(success ?
SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
packet_put_int(c->remote_id);
packet_send();
}
xfree(rtype);
}
void
client_set_session_ident(int id)
{
debug("client_set_session_ident: id %d", id);
session_ident = id;
channel_register_callback(id, SSH2_MSG_CHANNEL_REQUEST,
client_input_channel_req, (void *)0);
}

View File

@ -28,15 +28,77 @@
*/
#include "includes.h"
RCSID("$Id: compat.c,v 1.5 1999/11/24 16:15:24 markus Exp $");
RCSID("$Id: compat.c,v 1.13 2000/05/08 17:42:24 markus Exp $");
#include "ssh.h"
#include "packet.h"
#include "xmalloc.h"
#include "compat.h"
int compat13 = 0;
int compat20 = 0;
int datafellows = 0;
void
void
enable_compat20(void)
{
verbose("Enabling compatibility mode for protocol 2.0");
compat20 = 1;
}
void
enable_compat13(void)
{
verbose("Enabling compatibility mode for protocol 1.3");
compat13 = 1;
}
/* datafellows bug compatibility */
void
compat_datafellows(const char *version)
{
int i;
size_t len;
struct {
char *version;
int bugs;
} check[] = {
{"2.1.0", SSH_BUG_SIGBLOB|SSH_BUG_HMAC},
{"2.0.1", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|SSH_BUG_PUBKEYAUTH|SSH_BUG_X11FWD},
{NULL, 0}
};
for (i = 0; check[i].version; i++) {
len = strlen(check[i].version);
if (strlen(version) >= len &&
(strncmp(version, check[i].version, len) == 0)) {
verbose("datafellows: %.200s", version);
datafellows = check[i].bugs;
return;
}
}
}
#define SEP ","
int
proto_spec(const char *spec)
{
char *s = xstrdup(spec);
char *p;
int ret = SSH_PROTO_UNKNOWN;
for ((p = strtok(s, SEP)); p; (p = strtok(NULL, SEP))) {
switch(atoi(p)) {
case 1:
if (ret == SSH_PROTO_UNKNOWN)
ret |= SSH_PROTO_1_PREFERRED;
ret |= SSH_PROTO_1;
break;
case 2:
ret |= SSH_PROTO_2;
break;
default:
log("ignoring bad proto spec: '%s'.", p);
break;
}
}
xfree(s);
return ret;
}

View File

@ -26,10 +26,26 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* RCSID("$Id: compat.h,v 1.4 1999/11/24 16:15:24 markus Exp $"); */
/* RCSID("$Id: compat.h,v 1.7 2000/05/08 17:42:24 markus Exp $"); */
#ifndef COMPAT_H
#define COMPAT_H
#define SSH_PROTO_UNKNOWN 0x00
#define SSH_PROTO_1 0x01
#define SSH_PROTO_1_PREFERRED 0x02
#define SSH_PROTO_2 0x04
#define SSH_BUG_SIGBLOB 0x01
#define SSH_BUG_PUBKEYAUTH 0x02
#define SSH_BUG_HMAC 0x04
#define SSH_BUG_X11FWD 0x08
void enable_compat13(void);
void enable_compat20(void);
void compat_datafellows(const char *s);
int proto_spec(const char *spec);
extern int compat13;
extern int compat20;
extern int datafellows;
#endif

View File

@ -1,20 +1,20 @@
/*
*
*
* compress.c
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Wed Oct 25 22:12:46 1995 ylo
*
*
* Interface to packet compression for ssh.
*
*
*/
#include "includes.h"
RCSID("$Id: compress.c,v 1.5 2000/03/16 20:56:14 markus Exp $");
RCSID("$Id: compress.c,v 1.7 2000/04/14 10:30:31 markus Exp $");
#include "ssh.h"
#include "buffer.h"
@ -28,7 +28,7 @@ static z_stream outgoing_stream;
* (as in gzip).
*/
void
void
buffer_compress_init(int level)
{
debug("Enabling compression at level %d.", level);
@ -40,7 +40,7 @@ buffer_compress_init(int level)
/* Frees any data structures allocated for compression. */
void
void
buffer_compress_uninit()
{
debug("compress outgoing: raw data %lu, compressed %lu, factor %.2f",
@ -64,7 +64,7 @@ buffer_compress_uninit()
* receiver. This appends the compressed data to the output buffer.
*/
void
void
buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
{
char buf[4096];
@ -90,23 +90,13 @@ buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
case Z_OK:
/* Append compressed data to output_buffer. */
buffer_append(output_buffer, buf,
sizeof(buf) - outgoing_stream.avail_out);
sizeof(buf) - outgoing_stream.avail_out);
break;
case Z_STREAM_END:
fatal("buffer_compress: deflate returned Z_STREAM_END");
/* NOTREACHED */
case Z_STREAM_ERROR:
fatal("buffer_compress: deflate returned Z_STREAM_ERROR");
/* NOTREACHED */
case Z_BUF_ERROR:
fatal("buffer_compress: deflate returned Z_BUF_ERROR");
/* NOTREACHED */
default:
fatal("buffer_compress: deflate returned %d", status);
/* NOTREACHED */
}
}
while (outgoing_stream.avail_out == 0);
} while (outgoing_stream.avail_out == 0);
}
/*
@ -118,7 +108,7 @@ buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
* with that. This appends the uncompressed data to the output buffer.
*/
void
void
buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
{
char buf[4096];
@ -127,27 +117,17 @@ buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
incoming_stream.next_in = (unsigned char *) buffer_ptr(input_buffer);
incoming_stream.avail_in = buffer_len(input_buffer);
incoming_stream.next_out = (unsigned char *) buf;
incoming_stream.avail_out = sizeof(buf);
for (;;) {
/* Set up fixed-size output buffer. */
incoming_stream.next_out = (unsigned char *) buf;
incoming_stream.avail_out = sizeof(buf);
status = inflate(&incoming_stream, Z_PARTIAL_FLUSH);
switch (status) {
case Z_OK:
buffer_append(output_buffer, buf,
sizeof(buf) - incoming_stream.avail_out);
incoming_stream.next_out = (unsigned char *) buf;
incoming_stream.avail_out = sizeof(buf);
sizeof(buf) - incoming_stream.avail_out);
break;
case Z_STREAM_END:
fatal("buffer_uncompress: inflate returned Z_STREAM_END");
/* NOTREACHED */
case Z_DATA_ERROR:
fatal("buffer_uncompress: inflate returned Z_DATA_ERROR");
/* NOTREACHED */
case Z_STREAM_ERROR:
fatal("buffer_uncompress: inflate returned Z_STREAM_ERROR");
/* NOTREACHED */
case Z_BUF_ERROR:
/*
* Comments in zlib.h say that we should keep calling
@ -155,11 +135,9 @@ buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
* be the error that we get.
*/
return;
case Z_MEM_ERROR:
fatal("buffer_uncompress: inflate returned Z_MEM_ERROR");
/* NOTREACHED */
default:
fatal("buffer_uncompress: inflate returned %d", status);
/* NOTREACHED */
}
}
}

View File

@ -1,19 +1,19 @@
/*
*
*
* compress.h
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Wed Oct 25 22:12:46 1995 ylo
*
*
* Interface to packet compression for ssh.
*
*
*/
/* RCSID("$Id: compress.h,v 1.3 1999/11/24 19:53:46 markus Exp $"); */
/* RCSID("$Id: compress.h,v 1.4 2000/04/14 10:30:31 markus Exp $"); */
#ifndef COMPRESS_H
#define COMPRESS_H

View File

@ -1,19 +1,19 @@
/*
*
*
* crc32.h
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1992 Tatu Ylonen, Espoo, Finland
* All rights reserved
*
*
* Created: Tue Feb 11 14:37:27 1992 ylo
*
*
* Functions for computing 32-bit CRC.
*
*
*/
/* RCSID("$Id: crc32.h,v 1.4 1999/11/24 19:53:46 markus Exp $"); */
/* RCSID("$Id: crc32.h,v 1.5 2000/04/14 10:30:31 markus Exp $"); */
#ifndef CRC32_H
#define CRC32_H

78
crypto/openssh/dispatch.c Normal file
View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Markus Friedl.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$Id: dispatch.c,v 1.2 2000/04/14 10:30:31 markus Exp $");
#include "ssh.h"
#include "dispatch.h"
#include "packet.h"
#define DISPATCH_MIN 0
#define DISPATCH_MAX 255
dispatch_fn *dispatch[DISPATCH_MAX];
void
dispatch_protocol_error(int type, int plen)
{
error("Hm, dispatch protocol error: type %d plen %d", type, plen);
}
void
dispatch_init(dispatch_fn *dflt)
{
int i;
for (i = 0; i < DISPATCH_MAX; i++)
dispatch[i] = dflt;
}
void
dispatch_set(int type, dispatch_fn *fn)
{
dispatch[type] = fn;
}
void
dispatch_run(int mode, int *done)
{
for (;;) {
int plen;
int type;
if (mode == DISPATCH_BLOCK) {
type = packet_read(&plen);
} else {
type = packet_read_poll(&plen);
if (type == SSH_MSG_NONE)
return;
}
if (type > 0 && type < DISPATCH_MAX && dispatch[type] != NULL)
(*dispatch[type])(type, plen);
else
packet_disconnect("protocol error: rcvd type %d", type);
if (done != NULL && *done)
return;
}
}

11
crypto/openssh/dispatch.h Normal file
View File

@ -0,0 +1,11 @@
enum {
DISPATCH_BLOCK,
DISPATCH_NONBLOCK
};
typedef void dispatch_fn(int type, int plen);
void dispatch_init(dispatch_fn *dflt);
void dispatch_set(int type, dispatch_fn *fn);
void dispatch_run(int mode, int *done);
void dispatch_protocol_error(int type, int plen);

300
crypto/openssh/dsa.c Normal file
View File

@ -0,0 +1,300 @@
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Markus Friedl.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$Id: dsa.c,v 1.7 2000/05/08 17:42:24 markus Exp $");
#include "ssh.h"
#include "xmalloc.h"
#include "buffer.h"
#include "bufaux.h"
#include "compat.h"
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
#include <openssl/hmac.h>
#include "kex.h"
#include "key.h"
#include "uuencode.h"
#define INTBLOB_LEN 20
#define SIGBLOB_LEN (2*INTBLOB_LEN)
Key *
dsa_key_from_blob(
char *blob, int blen)
{
Buffer b;
char *ktype;
int rlen;
DSA *dsa;
Key *key;
#ifdef DEBUG_DSS
dump_base64(stderr, blob, blen);
#endif
/* fetch & parse DSA/DSS pubkey */
key = key_new(KEY_DSA);
dsa = key->dsa;
buffer_init(&b);
buffer_append(&b, blob, blen);
ktype = buffer_get_string(&b, NULL);
if (strcmp(KEX_DSS, ktype) != 0) {
error("dsa_key_from_blob: cannot handle type %s", ktype);
key_free(key);
return NULL;
}
buffer_get_bignum2(&b, dsa->p);
buffer_get_bignum2(&b, dsa->q);
buffer_get_bignum2(&b, dsa->g);
buffer_get_bignum2(&b, dsa->pub_key);
rlen = buffer_len(&b);
if(rlen != 0)
error("dsa_key_from_blob: remaining bytes in key blob %d", rlen);
buffer_free(&b);
debug("keytype %s", ktype);
#ifdef DEBUG_DSS
DSA_print_fp(stderr, dsa, 8);
#endif
return key;
}
int
dsa_make_key_blob(Key *key, unsigned char **blobp, unsigned int *lenp)
{
Buffer b;
int len;
unsigned char *buf;
if (key == NULL || key->type != KEY_DSA)
return 0;
buffer_init(&b);
buffer_put_cstring(&b, KEX_DSS);
buffer_put_bignum2(&b, key->dsa->p);
buffer_put_bignum2(&b, key->dsa->q);
buffer_put_bignum2(&b, key->dsa->g);
buffer_put_bignum2(&b, key->dsa->pub_key);
len = buffer_len(&b);
buf = xmalloc(len);
memcpy(buf, buffer_ptr(&b), len);
memset(buffer_ptr(&b), 0, len);
buffer_free(&b);
if (lenp != NULL)
*lenp = len;
if (blobp != NULL)
*blobp = buf;
return len;
}
int
dsa_sign(
Key *key,
unsigned char **sigp, int *lenp,
unsigned char *data, int datalen)
{
unsigned char *digest;
unsigned char *ret;
DSA_SIG *sig;
EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
unsigned int rlen;
unsigned int slen;
unsigned int len;
unsigned char sigblob[SIGBLOB_LEN];
Buffer b;
if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
error("dsa_sign: no DSA key");
return -1;
}
digest = xmalloc(evp_md->md_size);
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, data, datalen);
EVP_DigestFinal(&md, digest, NULL);
sig = DSA_do_sign(digest, evp_md->md_size, key->dsa);
if (sig == NULL) {
fatal("dsa_sign: cannot sign");
}
rlen = BN_num_bytes(sig->r);
slen = BN_num_bytes(sig->s);
if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
error("bad sig size %d %d", rlen, slen);
DSA_SIG_free(sig);
return -1;
}
debug("sig size %d %d", rlen, slen);
memset(sigblob, 0, SIGBLOB_LEN);
BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen);
BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen);
DSA_SIG_free(sig);
if (datafellows & SSH_BUG_SIGBLOB) {
debug("datafellows");
ret = xmalloc(SIGBLOB_LEN);
memcpy(ret, sigblob, SIGBLOB_LEN);
if (lenp != NULL)
*lenp = SIGBLOB_LEN;
if (sigp != NULL)
*sigp = ret;
} else {
/* ietf-drafts */
buffer_init(&b);
buffer_put_cstring(&b, KEX_DSS);
buffer_put_string(&b, sigblob, SIGBLOB_LEN);
len = buffer_len(&b);
ret = xmalloc(len);
memcpy(ret, buffer_ptr(&b), len);
buffer_free(&b);
if (lenp != NULL)
*lenp = len;
if (sigp != NULL)
*sigp = ret;
}
return 0;
}
int
dsa_verify(
Key *key,
unsigned char *signature, int signaturelen,
unsigned char *data, int datalen)
{
Buffer b;
unsigned char *digest;
DSA_SIG *sig;
EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
char *ktype;
unsigned char *sigblob;
char *txt;
unsigned int len;
int rlen;
int ret;
if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
error("dsa_verify: no DSA key");
return -1;
}
if (!(datafellows & SSH_BUG_SIGBLOB) &&
signaturelen == SIGBLOB_LEN) {
datafellows |= ~SSH_BUG_SIGBLOB;
log("autodetect SSH_BUG_SIGBLOB");
} else if ((datafellows & SSH_BUG_SIGBLOB) &&
signaturelen != SIGBLOB_LEN) {
log("autoremove SSH_BUG_SIGBLOB");
datafellows &= ~SSH_BUG_SIGBLOB;
}
debug("len %d datafellows %d", signaturelen, datafellows);
/* fetch signature */
if (datafellows & SSH_BUG_SIGBLOB) {
sigblob = signature;
len = signaturelen;
} else {
/* ietf-drafts */
buffer_init(&b);
buffer_append(&b, (char *) signature, signaturelen);
ktype = buffer_get_string(&b, NULL);
sigblob = (unsigned char *)buffer_get_string(&b, &len);
rlen = buffer_len(&b);
if(rlen != 0)
error("remaining bytes in signature %d", rlen);
buffer_free(&b);
}
if (len != SIGBLOB_LEN) {
fatal("bad sigbloblen %d != SIGBLOB_LEN", len);
}
/* parse signature */
sig = DSA_SIG_new();
sig->r = BN_new();
sig->s = BN_new();
BN_bin2bn(sigblob, INTBLOB_LEN, sig->r);
BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s);
if (!(datafellows & SSH_BUG_SIGBLOB)) {
memset(sigblob, 0, len);
xfree(sigblob);
}
/* sha1 the data */
digest = xmalloc(evp_md->md_size);
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, data, datalen);
EVP_DigestFinal(&md, digest, NULL);
ret = DSA_do_verify(digest, evp_md->md_size, sig, key->dsa);
memset(digest, 0, evp_md->md_size);
xfree(digest);
DSA_SIG_free(sig);
switch (ret) {
case 1:
txt = "correct";
break;
case 0:
txt = "incorrect";
break;
case -1:
default:
txt = "error";
break;
}
debug("dsa_verify: signature %s", txt);
return ret;
}
Key *
dsa_generate_key(unsigned int bits)
{
DSA *dsa = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL);
Key *k;
if (dsa == NULL) {
fatal("DSA_generate_parameters failed");
}
if (!DSA_generate_key(dsa)) {
fatal("DSA_generate_keys failed");
}
k = key_new(KEY_EMPTY);
k->type = KEY_DSA;
k->dsa = dsa;
return k;
}

22
crypto/openssh/dsa.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef DSA_H
#define DSA_H
Key *dsa_key_from_blob(char *blob, int blen);
int dsa_make_key_blob(Key *key, unsigned char **blobp, unsigned int *lenp);
int
dsa_sign(
Key *key,
unsigned char **sigp, int *lenp,
unsigned char *data, int datalen);
int
dsa_verify(
Key *key,
unsigned char *signature, int signaturelen,
unsigned char *data, int datalen);
Key *
dsa_generate_key(unsigned int bits);
#endif

View File

@ -1,19 +1,19 @@
/*
*
*
* getput.h
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Wed Jun 28 22:36:30 1995 ylo
*
*
* Macros for storing and retrieving data in msb first and lsb first order.
*
*
*/
/* RCSID("$Id: getput.h,v 1.2 1999/11/24 00:26:02 deraadt Exp $"); */
/* RCSID("$Id: getput.h,v 1.3 2000/04/14 10:30:31 markus Exp $"); */
#ifndef GETPUT_H
#define GETPUT_H
@ -21,7 +21,7 @@
/*------------ macros for storing/extracting msb first words -------------*/
#define GET_32BIT(cp) (((unsigned long)(unsigned char)(cp)[0] << 24) | \
((unsigned long)(unsigned char)(cp)[1] << 16) | \
((unsigned long)(unsigned char)(cp)[1] << 16) | \
((unsigned long)(unsigned char)(cp)[2] << 8) | \
((unsigned long)(unsigned char)(cp)[3]))

59
crypto/openssh/hmac.c Normal file
View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Markus Friedl.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$Id: hmac.c,v 1.2 2000/04/12 09:39:10 markus Exp $");
#include "xmalloc.h"
#include "ssh.h"
#include "getput.h"
#include <openssl/hmac.h>
unsigned char *
hmac(
EVP_MD *evp_md,
unsigned int seqno,
unsigned char *data, int datalen,
unsigned char *key, int keylen)
{
HMAC_CTX c;
static unsigned char m[EVP_MAX_MD_SIZE];
unsigned char b[4];
if (key == NULL)
fatal("hmac: no key");
HMAC_Init(&c, key, keylen, evp_md);
PUT_32BIT(b, seqno);
HMAC_Update(&c, b, sizeof b);
HMAC_Update(&c, data, datalen);
HMAC_Final(&c, m, NULL);
HMAC_cleanup(&c);
return(m);
}

11
crypto/openssh/hmac.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef HMAC_H
#define HMAC_H
unsigned char *
hmac(
EVP_MD *evp_md,
unsigned int seqno,
unsigned char *data, int datalen,
unsigned char *key, int len);
#endif

View File

@ -10,7 +10,7 @@
typedef enum {
HOST_OK, HOST_NEW, HOST_CHANGED
} HostStatus;
HostStatus
HostStatus
check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *found);
/*

424
crypto/openssh/kex.c Normal file
View File

@ -0,0 +1,424 @@
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Markus Friedl.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$Id: kex.c,v 1.6 2000/05/08 17:42:25 markus Exp $");
#include "ssh.h"
#include "ssh2.h"
#include "xmalloc.h"
#include "buffer.h"
#include "bufaux.h"
#include "cipher.h"
#include "compat.h"
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/crypto.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/pem.h>
#include "kex.h"
Buffer *
kex_init(char *myproposal[PROPOSAL_MAX])
{
char c = 0;
unsigned char cookie[16];
u_int32_t rand = 0;
int i;
Buffer *ki = xmalloc(sizeof(*ki));
for (i = 0; i < 16; i++) {
if (i % 4 == 0)
rand = arc4random();
cookie[i] = rand & 0xff;
rand >>= 8;
}
buffer_init(ki);
buffer_append(ki, (char *)cookie, sizeof cookie);
for (i = 0; i < PROPOSAL_MAX; i++)
buffer_put_cstring(ki, myproposal[i]);
buffer_append(ki, &c, 1); /* boolean first_kex_packet_follows */
buffer_put_int(ki, 0); /* uint32 0 (reserved for future extension) */
return ki;
}
/* diffie-hellman-group1-sha1 */
int
dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
{
int i;
int n = BN_num_bits(dh_pub);
int bits_set = 0;
/* we only accept g==2 */
if (!BN_is_word(dh->g, 2)) {
log("invalid DH base != 2");
return 0;
}
if (dh_pub->neg) {
log("invalid public DH value: negativ");
return 0;
}
for (i = 0; i <= n; i++)
if (BN_is_bit_set(dh_pub, i))
bits_set++;
debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
/* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
return 1;
log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
return 0;
}
DH *
dh_new_group1()
{
static char *group1 =
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
"FFFFFFFF" "FFFFFFFF";
DH *dh;
int ret, tries = 0;
dh = DH_new();
if(dh == NULL)
fatal("DH_new");
ret = BN_hex2bn(&dh->p, group1);
if(ret<0)
fatal("BN_hex2bn");
dh->g = BN_new();
if(dh->g == NULL)
fatal("DH_new g");
BN_set_word(dh->g, 2);
do {
if (DH_generate_key(dh) == 0)
fatal("DH_generate_key");
if (tries++ > 10)
fatal("dh_new_group1: too many bad keys: giving up");
} while (!dh_pub_is_valid(dh, dh->pub_key));
return dh;
}
void
bignum_print(BIGNUM *b)
{
BN_print_fp(stderr,b);
}
void
dump_digest(unsigned char *digest, int len)
{
int i;
for (i = 0; i< len; i++){
fprintf(stderr, "%02x", digest[i]);
if(i%2!=0)
fprintf(stderr, " ");
}
fprintf(stderr, "\n");
}
unsigned char *
kex_hash(
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
char *serverhostkeyblob, int sbloblen,
BIGNUM *client_dh_pub,
BIGNUM *server_dh_pub,
BIGNUM *shared_secret)
{
Buffer b;
static unsigned char digest[EVP_MAX_MD_SIZE];
EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
buffer_init(&b);
buffer_put_string(&b, client_version_string, strlen(client_version_string));
buffer_put_string(&b, server_version_string, strlen(server_version_string));
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
buffer_put_int(&b, ckexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, ckexinit, ckexinitlen);
buffer_put_int(&b, skexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, skexinit, skexinitlen);
buffer_put_string(&b, serverhostkeyblob, sbloblen);
buffer_put_bignum2(&b, client_dh_pub);
buffer_put_bignum2(&b, server_dh_pub);
buffer_put_bignum2(&b, shared_secret);
#ifdef DEBUG_KEX
buffer_dump(&b);
#endif
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
EVP_DigestFinal(&md, digest, NULL);
buffer_free(&b);
#ifdef DEBUG_KEX
dump_digest(digest, evp_md->md_size);
#endif
return digest;
}
unsigned char *
derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
{
Buffer b;
EVP_MD *evp_md = EVP_sha1();
EVP_MD_CTX md;
char c = id;
int have;
int mdsz = evp_md->md_size;
unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
buffer_init(&b);
buffer_put_bignum2(&b, shared_secret);
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */
EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */
EVP_DigestUpdate(&md, &c, 1); /* key id */
EVP_DigestUpdate(&md, hash, mdsz); /* session id */
EVP_DigestFinal(&md, digest, NULL);
/* expand */
for (have = mdsz; need > have; have += mdsz) {
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
EVP_DigestUpdate(&md, hash, mdsz);
EVP_DigestUpdate(&md, digest, have);
EVP_DigestFinal(&md, digest + have, NULL);
}
buffer_free(&b);
#ifdef DEBUG_KEX
fprintf(stderr, "Digest '%c'== ", c);
dump_digest(digest, need);
#endif
return digest;
}
#define NKEYS 6
#define MAX_PROP 20
#define SEP ","
char *
get_match(char *client, char *server)
{
char *sproposals[MAX_PROP];
char *p;
int i, j, nproposals;
for ((p = strtok(server, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
if (i < MAX_PROP)
sproposals[i] = p;
else
break;
}
nproposals = i;
for ((p = strtok(client, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
for (j = 0; j < nproposals; j++)
if (strcmp(p, sproposals[j]) == 0)
return xstrdup(p);
}
return NULL;
}
void
choose_enc(Enc *enc, char *client, char *server)
{
char *name = get_match(client, server);
if (name == NULL)
fatal("no matching cipher found: client %s server %s", client, server);
enc->type = cipher_number(name);
switch (enc->type) {
case SSH_CIPHER_3DES_CBC:
enc->key_len = 24;
enc->iv_len = 8;
enc->block_size = 8;
break;
case SSH_CIPHER_BLOWFISH_CBC:
case SSH_CIPHER_CAST128_CBC:
enc->key_len = 16;
enc->iv_len = 8;
enc->block_size = 8;
break;
case SSH_CIPHER_ARCFOUR:
enc->key_len = 16;
enc->iv_len = 0;
enc->block_size = 8;
break;
default:
fatal("unsupported cipher %s", name);
}
enc->name = name;
enc->enabled = 0;
enc->iv = NULL;
enc->key = NULL;
}
void
choose_mac(Mac *mac, char *client, char *server)
{
char *name = get_match(client, server);
if (name == NULL)
fatal("no matching mac found: client %s server %s", client, server);
if (strcmp(name, "hmac-md5") == 0) {
mac->md = EVP_md5();
} else if (strcmp(name, "hmac-sha1") == 0) {
mac->md = EVP_sha1();
} else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
mac->md = EVP_ripemd160();
} else {
fatal("unsupported mac %s", name);
}
mac->name = name;
mac->mac_len = mac->md->md_size;
mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
mac->key = NULL;
mac->enabled = 0;
}
void
choose_comp(Comp *comp, char *client, char *server)
{
char *name = get_match(client, server);
if (name == NULL)
fatal("no matching comp found: client %s server %s", client, server);
if (strcmp(name, "zlib") == 0) {
comp->type = 1;
} else if (strcmp(name, "none") == 0) {
comp->type = 0;
} else {
fatal("unsupported comp %s", name);
}
comp->name = name;
}
void
choose_kex(Kex *k, char *client, char *server)
{
k->name = get_match(client, server);
if (k->name == NULL)
fatal("no kex alg");
if (strcmp(k->name, KEX_DH1) != 0)
fatal("bad kex alg %s", k->name);
}
void
choose_hostkeyalg(Kex *k, char *client, char *server)
{
k->hostkeyalg = get_match(client, server);
if (k->hostkeyalg == NULL)
fatal("no hostkey alg");
if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
fatal("bad hostkey alg %s", k->hostkeyalg);
}
Kex *
kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
{
int i;
int mode;
int ctos; /* direction: if true client-to-server */
int need;
Kex *k;
k = xmalloc(sizeof(*k));
memset(k, 0, sizeof(*k));
k->server = server;
for (mode = 0; mode < MODE_MAX; mode++) {
int nenc, nmac, ncomp;
ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
debug("kex: %s %s %s %s",
ctos ? "client->server" : "server->client",
k->enc[mode].name,
k->mac[mode].name,
k->comp[mode].name);
}
choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
for (i = 0; i < PROPOSAL_MAX; i++) {
xfree(cprop[i]);
xfree(sprop[i]);
}
need = 0;
for (mode = 0; mode < MODE_MAX; mode++) {
if (need < k->enc[mode].key_len)
need = k->enc[mode].key_len;
if (need < k->enc[mode].iv_len)
need = k->enc[mode].iv_len;
if (need < k->mac[mode].key_len)
need = k->mac[mode].key_len;
}
/* need runden? */
#define WE_NEED 32
k->we_need = WE_NEED;
k->we_need = need;
return k;
}
int
kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
{
int i;
int mode;
int ctos;
unsigned char *keys[NKEYS];
for (i = 0; i < NKEYS; i++)
keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
for (mode = 0; mode < MODE_MAX; mode++) {
ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
k->enc[mode].iv = keys[ctos ? 0 : 1];
k->enc[mode].key = keys[ctos ? 2 : 3];
k->mac[mode].key = keys[ctos ? 4 : 5];
}
return 0;
}

112
crypto/openssh/kex.h Normal file
View File

@ -0,0 +1,112 @@
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Markus Friedl.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef KEX_H
#define KEX_H
#define KEX_DH1 "diffie-hellman-group1-sha1"
#define KEX_DSS "ssh-dss"
enum kex_init_proposals {
PROPOSAL_KEX_ALGS,
PROPOSAL_SERVER_HOST_KEY_ALGS,
PROPOSAL_ENC_ALGS_CTOS,
PROPOSAL_ENC_ALGS_STOC,
PROPOSAL_MAC_ALGS_CTOS,
PROPOSAL_MAC_ALGS_STOC,
PROPOSAL_COMP_ALGS_CTOS,
PROPOSAL_COMP_ALGS_STOC,
PROPOSAL_LANG_CTOS,
PROPOSAL_LANG_STOC,
PROPOSAL_MAX
};
enum kex_modes {
MODE_IN,
MODE_OUT,
MODE_MAX
};
typedef struct Kex Kex;
typedef struct Mac Mac;
typedef struct Comp Comp;
typedef struct Enc Enc;
struct Enc {
int type;
int enabled;
int block_size;
unsigned char *key;
unsigned char *iv;
int key_len;
int iv_len;
char *name;
};
struct Mac {
EVP_MD *md;
int enabled;
int mac_len;
unsigned char *key;
int key_len;
char *name;
};
struct Comp {
int type;
int enabled;
char *name;
};
struct Kex {
Enc enc [MODE_MAX];
Mac mac [MODE_MAX];
Comp comp[MODE_MAX];
int we_need;
int server;
char *name;
char *hostkeyalg;
};
Buffer *kex_init(char *myproposal[PROPOSAL_MAX]);
int dh_pub_is_valid(DH *dh, BIGNUM *dh_pub);
DH *dh_new_group1();
Kex *kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server);
int kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret);
void bignum_print(BIGNUM *b);
void packet_set_kex(Kex *k);
unsigned char *
kex_hash(
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
char *serverhostkeyblob, int sbloblen,
BIGNUM *client_dh_pub,
BIGNUM *server_dh_pub,
BIGNUM *shared_secret);
#endif

View File

@ -17,7 +17,9 @@ Key *key_new(int type);
void key_free(Key *k);
int key_equal(Key *a, Key *b);
char *key_fingerprint(Key *k);
char *key_type(Key *k);
int key_write(Key *key, FILE *f);
int key_read(Key *key, unsigned int bits, char **cpp);
unsigned int
key_read(Key *key, char **cpp);
#endif

View File

@ -5,7 +5,7 @@ SRCS= authfd.c authfile.c bufaux.c buffer.c canohost.c channels.c \
cipher.c compat.c compress.c crc32.c deattack.c fingerprint.c \
hostfile.c log.c match.c mpaux.c nchan.c packet.c readpass.c \
rsa.c tildexpand.c ttymodes.c uidswap.c xmalloc.c atomicio.c \
key.c
key.c dispatch.c dsa.c kex.c hmac.c uuencode.c
NOPROFILE= yes
NOPIC= yes

View File

@ -1,21 +1,21 @@
/*
*
*
* log-client.c
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Mon Mar 20 21:13:40 1995 ylo
*
*
* Client-side versions of debug(), log(), etc. These print to stderr.
* This is a stripped down version of log-server.c.
*
*
*/
#include "includes.h"
RCSID("$Id: log-client.c,v 1.7 2000/02/27 18:50:09 deraadt Exp $");
RCSID("$Id: log-client.c,v 1.8 2000/04/14 10:30:31 markus Exp $");
#include "xmalloc.h"
#include "ssh.h"

View File

@ -1,21 +1,21 @@
/*
*
*
* log-server.c
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Mon Mar 20 21:19:30 1995 ylo
*
*
* Server-side versions of debug(), log(), etc. These normally send the output
* to the system log.
*
*
*/
#include "includes.h"
RCSID("$Id: log-server.c,v 1.12 2000/02/27 18:50:09 deraadt Exp $");
RCSID("$Id: log-server.c,v 1.14 2000/04/14 10:30:31 markus Exp $");
#include <syslog.h>
#include "packet.h"
@ -32,7 +32,7 @@ static int log_facility = LOG_AUTH;
* level logging level
*/
void
void
log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
{
switch (level) {
@ -132,9 +132,11 @@ do_log(LogLevel level, const char *fmt, va_list args)
} else {
vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
}
if (log_on_stderr)
if (log_on_stderr) {
fprintf(stderr, "%s\n", msgbuf);
openlog(__progname, LOG_PID, log_facility);
syslog(pri, "%.500s", msgbuf);
closelog();
} else {
openlog(__progname, LOG_PID, log_facility);
syslog(pri, "%.500s", msgbuf);
closelog();
}
}

View File

@ -1,20 +1,20 @@
/*
*
*
* match.c
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Thu Jun 22 01:17:50 1995 ylo
*
*
* Simple pattern matching, with '*' and '?' as wildcards.
*
*
*/
#include "includes.h"
RCSID("$Id: match.c,v 1.5 2000/03/23 22:15:33 markus Exp $");
RCSID("$Id: match.c,v 1.6 2000/04/14 10:30:31 markus Exp $");
#include "ssh.h"
@ -23,7 +23,7 @@ RCSID("$Id: match.c,v 1.5 2000/03/23 22:15:33 markus Exp $");
* and * as wildcards), and zero if it does not match.
*/
int
int
match_pattern(const char *s, const char *pattern)
{
for (;;) {

View File

@ -1,19 +1,19 @@
/*
*
*
* mpaux.h
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Sun Jul 16 04:29:30 1995 ylo
*
*
* This file contains various auxiliary functions related to multiple
* precision integers.
*/
/* RCSID("$Id: mpaux.h,v 1.5 1999/11/24 19:53:48 markus Exp $"); */
/* RCSID("$Id: mpaux.h,v 1.6 2000/04/14 10:30:32 markus Exp $"); */
#ifndef MPAUX_H
#define MPAUX_H
@ -23,7 +23,7 @@
* session id is computed by concatenating the linearized, msb first
* representations of host_key_n, session_key_n, and the cookie.
*/
void
void
compute_session_id(unsigned char session_id[16],
unsigned char cookie[8],
BIGNUM * host_key_n,

View File

@ -0,0 +1,20 @@
#define KEX_DEFAULT_KEX "diffie-hellman-group1-sha1"
#define KEX_DEFAULT_PK_ALG "ssh-dss"
#define KEX_DEFAULT_ENCRYPT "3des-cbc,blowfish-cbc,arcfour,cast128-cbc"
#define KEX_DEFAULT_MAC "hmac-sha1,hmac-md5,hmac-ripemd160@openssh.com"
#define KEX_DEFAULT_COMP "zlib,none"
#define KEX_DEFAULT_LANG ""
static const char *myproposal[PROPOSAL_MAX] = {
KEX_DEFAULT_KEX,
KEX_DEFAULT_PK_ALG,
KEX_DEFAULT_ENCRYPT,
KEX_DEFAULT_ENCRYPT,
KEX_DEFAULT_MAC,
KEX_DEFAULT_MAC,
KEX_DEFAULT_COMP,
KEX_DEFAULT_COMP,
KEX_DEFAULT_LANG,
KEX_DEFAULT_LANG
};

View File

@ -28,7 +28,7 @@
*/
#include "includes.h"
RCSID("$Id: nchan.c,v 1.10 2000/01/10 10:15:28 markus Exp $");
RCSID("$Id: nchan.c,v 1.17 2000/05/08 17:44:54 markus Exp $");
#include "ssh.h"
@ -37,143 +37,192 @@ RCSID("$Id: nchan.c,v 1.10 2000/01/10 10:15:28 markus Exp $");
#include "channels.h"
#include "nchan.h"
static void chan_send_ieof(Channel *c);
static void chan_send_oclose(Channel *c);
static void chan_shutdown_write(Channel *c);
static void chan_shutdown_read(Channel *c);
static void chan_delete_if_full_closed(Channel *c);
#include "ssh2.h"
#include "compat.h"
/* functions manipulating channel states */
/*
* EVENTS update channel input/output states execute ACTIONS
*/
/* events concerning the INPUT from socket for channel (istate) */
void
chan_rcvd_oclose(Channel *c)
chan_event_fn *chan_rcvd_oclose = NULL;
chan_event_fn *chan_read_failed = NULL;
chan_event_fn *chan_ibuf_empty = NULL;
/* events concerning the OUTPUT from channel for socket (ostate) */
chan_event_fn *chan_rcvd_ieof = NULL;
chan_event_fn *chan_write_failed = NULL;
chan_event_fn *chan_obuf_empty = NULL;
/*
* ACTIONS: should never update the channel states
*/
static void chan_send_ieof1(Channel *c);
static void chan_send_oclose1(Channel *c);
static void chan_send_close2(Channel *c);
static void chan_send_eof2(Channel *c);
/* channel cleanup */
chan_event_fn *chan_delete_if_full_closed = NULL;
/* helper */
static void chan_shutdown_write(Channel *c);
static void chan_shutdown_read(Channel *c);
/*
* SSH1 specific implementation of event functions
*/
static void
chan_rcvd_oclose1(Channel *c)
{
debug("channel %d: rcvd oclose", c->self);
switch (c->istate) {
case CHAN_INPUT_WAIT_OCLOSE:
debug("channel %d: INPUT_WAIT_OCLOSE -> INPUT_CLOSED [rcvd OCLOSE]", c->self);
debug("channel %d: input wait_oclose -> closed", c->self);
c->istate = CHAN_INPUT_CLOSED;
break;
case CHAN_INPUT_OPEN:
debug("channel %d: INPUT_OPEN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
debug("channel %d: input open -> closed", c->self);
chan_shutdown_read(c);
chan_send_ieof(c);
chan_send_ieof1(c);
c->istate = CHAN_INPUT_CLOSED;
break;
case CHAN_INPUT_WAIT_DRAIN:
/* both local read_failed and remote write_failed */
log("channel %d: INPUT_WAIT_DRAIN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
chan_send_ieof(c);
log("channel %d: input drain -> closed", c->self);
chan_send_ieof1(c);
c->istate = CHAN_INPUT_CLOSED;
break;
default:
error("protocol error: chan_rcvd_oclose %d for istate %d", c->self, c->istate);
error("channel %d: protocol error: chan_rcvd_oclose for istate %d",
c->self, c->istate);
return;
}
chan_delete_if_full_closed(c);
}
void
chan_read_failed(Channel *c)
static void
chan_read_failed_12(Channel *c)
{
debug("channel %d: read failed", c->self);
switch (c->istate) {
case CHAN_INPUT_OPEN:
debug("channel %d: INPUT_OPEN -> INPUT_WAIT_DRAIN [read failed]", c->self);
debug("channel %d: input open -> drain", c->self);
chan_shutdown_read(c);
c->istate = CHAN_INPUT_WAIT_DRAIN;
if (buffer_len(&c->input) == 0) {
debug("channel %d: input: no drain shortcut", c->self);
chan_ibuf_empty(c);
}
break;
default:
error("internal error: we do not read, but chan_read_failed %d for istate %d",
c->self, c->istate);
error("channel %d: internal error: we do not read, but chan_read_failed for istate %d",
c->self, c->istate);
break;
}
}
void
chan_ibuf_empty(Channel *c)
static void
chan_ibuf_empty1(Channel *c)
{
debug("channel %d: ibuf empty", c->self);
if (buffer_len(&c->input)) {
error("internal error: chan_ibuf_empty %d for non empty buffer", c->self);
error("channel %d: internal error: chan_ibuf_empty for non empty buffer",
c->self);
return;
}
switch (c->istate) {
case CHAN_INPUT_WAIT_DRAIN:
debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_WAIT_OCLOSE [inbuf empty, send IEOF]", c->self);
chan_send_ieof(c);
debug("channel %d: input drain -> wait_oclose", c->self);
chan_send_ieof1(c);
c->istate = CHAN_INPUT_WAIT_OCLOSE;
break;
default:
error("internal error: chan_ibuf_empty %d for istate %d", c->self, c->istate);
error("channel %d: internal error: chan_ibuf_empty for istate %d",
c->self, c->istate);
break;
}
}
/* events concerning the OUTPUT from channel for socket (ostate) */
void
chan_rcvd_ieof(Channel *c)
static void
chan_rcvd_ieof1(Channel *c)
{
debug("channel %d: rcvd ieof", c->self);
if (c->type != SSH_CHANNEL_OPEN) {
debug("channel %d: non-open", c->self);
if (c->istate == CHAN_INPUT_OPEN) {
debug("channel %d: non-open: input open -> wait_oclose", c->self);
chan_shutdown_read(c);
chan_send_ieof1(c);
c->istate = CHAN_INPUT_WAIT_OCLOSE;
} else {
error("channel %d: istate %d != open", c->self, c->istate);
}
if (c->ostate == CHAN_OUTPUT_OPEN) {
debug("channel %d: non-open: output open -> closed", c->self);
chan_send_oclose1(c);
c->ostate = CHAN_OUTPUT_CLOSED;
} else {
error("channel %d: ostate %d != open", c->self, c->ostate);
}
return;
}
switch (c->ostate) {
case CHAN_OUTPUT_OPEN:
debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_DRAIN [rvcd IEOF]", c->self);
debug("channel %d: output open -> drain", c->self);
c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
break;
case CHAN_OUTPUT_WAIT_IEOF:
debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self);
debug("channel %d: output wait_ieof -> closed", c->self);
c->ostate = CHAN_OUTPUT_CLOSED;
chan_delete_if_full_closed(c);
break;
default:
error("protocol error: chan_rcvd_ieof %d for ostate %d", c->self, c->ostate);
error("channel %d: protocol error: chan_rcvd_ieof for ostate %d",
c->self, c->ostate);
break;
}
}
void
chan_write_failed(Channel *c)
static void
chan_write_failed1(Channel *c)
{
debug("channel %d: write failed", c->self);
switch (c->ostate) {
case CHAN_OUTPUT_OPEN:
debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_IEOF [write failed]", c->self);
chan_send_oclose(c);
debug("channel %d: output open -> wait_ieof", c->self);
chan_send_oclose1(c);
c->ostate = CHAN_OUTPUT_WAIT_IEOF;
break;
case CHAN_OUTPUT_WAIT_DRAIN:
debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self);
chan_send_oclose(c);
debug("channel %d: output wait_drain -> closed", c->self);
chan_send_oclose1(c);
c->ostate = CHAN_OUTPUT_CLOSED;
chan_delete_if_full_closed(c);
break;
default:
error("internal error: chan_write_failed %d for ostate %d", c->self, c->ostate);
error("channel %d: internal error: chan_write_failed for ostate %d",
c->self, c->ostate);
break;
}
}
void
chan_obuf_empty(Channel *c)
static void
chan_obuf_empty1(Channel *c)
{
debug("channel %d: obuf empty", c->self);
if (buffer_len(&c->output)) {
debug("internal error: chan_obuf_empty %d for non empty buffer", c->self);
error("channel %d: internal error: chan_obuf_empty for non empty buffer",
c->self);
return;
}
switch (c->ostate) {
case CHAN_OUTPUT_WAIT_DRAIN:
debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self);
chan_send_oclose(c);
debug("channel %d: output drain -> closed", c->self);
chan_send_oclose1(c);
c->ostate = CHAN_OUTPUT_CLOSED;
chan_delete_if_full_closed(c);
break;
default:
error("internal error: chan_obuf_empty %d for ostate %d", c->self, c->ostate);
error("channel %d: internal error: chan_obuf_empty for ostate %d",
c->self, c->ostate);
break;
}
}
/*
* ACTIONS: should never update the channel states: c->istate or c->ostate
*/
static void
chan_send_ieof(Channel *c)
chan_send_ieof1(Channel *c)
{
debug("channel %d: send ieof", c->self);
switch (c->istate) {
case CHAN_INPUT_OPEN:
case CHAN_INPUT_WAIT_DRAIN:
@ -182,13 +231,15 @@ chan_send_ieof(Channel *c)
packet_send();
break;
default:
error("internal error: channel %d: cannot send IEOF for istate %d", c->self, c->istate);
error("channel %d: internal error: cannot send ieof for istate %d",
c->self, c->istate);
break;
}
}
static void
chan_send_oclose(Channel *c)
chan_send_oclose1(Channel *c)
{
debug("channel %d: send oclose", c->self);
switch (c->ostate) {
case CHAN_OUTPUT_OPEN:
case CHAN_OUTPUT_WAIT_DRAIN:
@ -199,40 +250,246 @@ chan_send_oclose(Channel *c)
packet_send();
break;
default:
error("internal error: channel %d: cannot send OCLOSE for ostate %d", c->self, c->istate);
error("channel %d: internal error: cannot send oclose for ostate %d",
c->self, c->ostate);
break;
}
}
static void
chan_delete_if_full_closed1(Channel *c)
{
if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
debug("channel %d: full closed", c->self);
channel_free(c->self);
}
}
/*
* the same for SSH2
*/
static void
chan_rcvd_oclose2(Channel *c)
{
debug("channel %d: rcvd close", c->self);
if (c->flags & CHAN_CLOSE_RCVD)
error("channel %d: protocol error: close rcvd twice", c->self);
c->flags |= CHAN_CLOSE_RCVD;
if (c->type == SSH_CHANNEL_LARVAL) {
/* tear down larval channels immediately */
c->ostate = CHAN_OUTPUT_CLOSED;
c->istate = CHAN_INPUT_CLOSED;
return;
}
switch (c->ostate) {
case CHAN_OUTPUT_OPEN:
/* wait until a data from the channel is consumed if a CLOSE is received */
debug("channel %d: output open -> drain", c->self);
c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
break;
}
switch (c->istate) {
case CHAN_INPUT_OPEN:
debug("channel %d: input open -> closed", c->self);
chan_shutdown_read(c);
break;
case CHAN_INPUT_WAIT_DRAIN:
debug("channel %d: input drain -> closed", c->self);
chan_send_eof2(c);
break;
}
c->istate = CHAN_INPUT_CLOSED;
}
static void
chan_ibuf_empty2(Channel *c)
{
debug("channel %d: ibuf empty", c->self);
if (buffer_len(&c->input)) {
error("channel %d: internal error: chan_ibuf_empty for non empty buffer",
c->self);
return;
}
switch (c->istate) {
case CHAN_INPUT_WAIT_DRAIN:
debug("channel %d: input drain -> closed", c->self);
if (!(c->flags & CHAN_CLOSE_SENT))
chan_send_eof2(c);
c->istate = CHAN_INPUT_CLOSED;
break;
default:
error("channel %d: internal error: chan_ibuf_empty for istate %d",
c->self, c->istate);
break;
}
}
static void
chan_rcvd_ieof2(Channel *c)
{
debug("channel %d: rcvd eof", c->self);
if (c->ostate == CHAN_OUTPUT_OPEN) {
debug("channel %d: output open -> drain", c->self);
c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
}
}
static void
chan_write_failed2(Channel *c)
{
debug("channel %d: write failed", c->self);
switch (c->ostate) {
case CHAN_OUTPUT_OPEN:
debug("channel %d: output open -> closed", c->self);
chan_shutdown_write(c); /* ?? */
c->ostate = CHAN_OUTPUT_CLOSED;
break;
case CHAN_OUTPUT_WAIT_DRAIN:
debug("channel %d: output drain -> closed", c->self);
chan_shutdown_write(c);
c->ostate = CHAN_OUTPUT_CLOSED;
break;
default:
error("channel %d: internal error: chan_write_failed for ostate %d",
c->self, c->ostate);
break;
}
}
static void
chan_obuf_empty2(Channel *c)
{
debug("channel %d: obuf empty", c->self);
if (buffer_len(&c->output)) {
error("internal error: chan_obuf_empty %d for non empty buffer",
c->self);
return;
}
switch (c->ostate) {
case CHAN_OUTPUT_WAIT_DRAIN:
debug("channel %d: output drain -> closed", c->self);
chan_shutdown_write(c);
c->ostate = CHAN_OUTPUT_CLOSED;
break;
default:
error("channel %d: internal error: chan_obuf_empty for ostate %d",
c->self, c->ostate);
break;
}
}
static void
chan_send_eof2(Channel *c)
{
debug("channel %d: send eof", c->self);
switch (c->istate) {
case CHAN_INPUT_WAIT_DRAIN:
packet_start(SSH2_MSG_CHANNEL_EOF);
packet_put_int(c->remote_id);
packet_send();
break;
default:
error("channel %d: internal error: cannot send eof for istate %d",
c->self, c->istate);
break;
}
}
static void
chan_send_close2(Channel *c)
{
debug("channel %d: send close", c->self);
if (c->ostate != CHAN_OUTPUT_CLOSED ||
c->istate != CHAN_INPUT_CLOSED) {
error("channel %d: internal error: cannot send close for istate/ostate %d/%d",
c->self, c->istate, c->ostate);
} else if (c->flags & CHAN_CLOSE_SENT) {
error("channel %d: internal error: already sent close", c->self);
} else {
packet_start(SSH2_MSG_CHANNEL_CLOSE);
packet_put_int(c->remote_id);
packet_send();
c->flags |= CHAN_CLOSE_SENT;
}
}
static void
chan_delete_if_full_closed2(Channel *c)
{
if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
if (!(c->flags & CHAN_CLOSE_SENT)) {
chan_send_close2(c);
}
if ((c->flags & CHAN_CLOSE_SENT) &&
(c->flags & CHAN_CLOSE_RCVD)) {
debug("channel %d: full closed2", c->self);
channel_free(c->self);
}
}
}
/* shared */
void
chan_init_iostates(Channel *c)
{
c->ostate = CHAN_OUTPUT_OPEN;
c->istate = CHAN_INPUT_OPEN;
c->flags = 0;
}
/* init */
void
chan_init(void)
{
if (compat20) {
chan_rcvd_oclose = chan_rcvd_oclose2;
chan_read_failed = chan_read_failed_12;
chan_ibuf_empty = chan_ibuf_empty2;
chan_rcvd_ieof = chan_rcvd_ieof2;
chan_write_failed = chan_write_failed2;
chan_obuf_empty = chan_obuf_empty2;
chan_delete_if_full_closed = chan_delete_if_full_closed2;
} else {
chan_rcvd_oclose = chan_rcvd_oclose1;
chan_read_failed = chan_read_failed_12;
chan_ibuf_empty = chan_ibuf_empty1;
chan_rcvd_ieof = chan_rcvd_ieof1;
chan_write_failed = chan_write_failed1;
chan_obuf_empty = chan_obuf_empty1;
chan_delete_if_full_closed = chan_delete_if_full_closed1;
}
}
/* helper */
static void
chan_shutdown_write(Channel *c)
{
buffer_consume(&c->output, buffer_len(&c->output));
if (compat20 && c->type == SSH_CHANNEL_LARVAL)
return;
/* shutdown failure is allowed if write failed already */
debug("channel %d: shutdown_write", c->self);
if (shutdown(c->sock, SHUT_WR) < 0)
debug("chan_shutdown_write failed for #%d/fd%d: %.100s",
c->self, c->sock, strerror(errno));
debug("channel %d: close_write", c->self);
if (c->sock != -1) {
if (shutdown(c->sock, SHUT_WR) < 0)
debug("channel %d: chan_shutdown_write: shutdown() failed for fd%d: %.100s",
c->self, c->sock, strerror(errno));
} else {
if (close(c->wfd) < 0)
log("channel %d: chan_shutdown_write: close() failed for fd%d: %.100s",
c->self, c->wfd, strerror(errno));
c->wfd = -1;
}
}
static void
chan_shutdown_read(Channel *c)
{
debug("channel %d: shutdown_read", c->self);
if (shutdown(c->sock, SHUT_RD) < 0)
error("chan_shutdown_read failed for #%d/fd%d [i%d o%d]: %.100s",
c->self, c->sock, c->istate, c->ostate, strerror(errno));
}
static void
chan_delete_if_full_closed(Channel *c)
{
if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
debug("channel %d: full closed", c->self);
channel_free(c->self);
if (compat20 && c->type == SSH_CHANNEL_LARVAL)
return;
debug("channel %d: close_read", c->self);
if (c->sock != -1) {
if (shutdown(c->sock, SHUT_RD) < 0)
error("channel %d: chan_shutdown_read: shutdown() failed for fd%d [i%d o%d]: %.100s",
c->self, c->sock, c->istate, c->ostate, strerror(errno));
} else {
if (close(c->rfd) < 0)
log("channel %d: chan_shutdown_read: close() failed for fd%d: %.100s",
c->self, c->rfd, strerror(errno));
c->rfd = -1;
}
}
void
chan_init_iostates(Channel *c)
{
c->ostate = CHAN_OUTPUT_OPEN;
c->istate = CHAN_INPUT_OPEN;
}

View File

@ -27,7 +27,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* RCSID("$Id: nchan.h,v 1.5 1999/11/24 16:15:25 markus Exp $"); */
/* RCSID("$Id: nchan.h,v 1.7 2000/04/03 07:07:15 markus Exp $"); */
#ifndef NCHAN_H
#define NCHAN_H
@ -72,15 +72,25 @@
#define CHAN_OUTPUT_WAIT_IEOF 0x40
#define CHAN_OUTPUT_CLOSED 0x80
/* EVENTS for the input state */
void chan_rcvd_oclose(Channel * c);
void chan_read_failed(Channel * c);
void chan_ibuf_empty(Channel * c);
#define CHAN_CLOSE_SENT 0x01
#define CHAN_CLOSE_RCVD 0x02
/* EVENTS for the output state */
void chan_rcvd_ieof(Channel * c);
void chan_write_failed(Channel * c);
void chan_obuf_empty(Channel * c);
/* Channel EVENTS */
typedef void chan_event_fn(Channel * c);
/* for the input state */
extern chan_event_fn *chan_rcvd_oclose;
extern chan_event_fn *chan_read_failed;
extern chan_event_fn *chan_ibuf_empty;
/* for the output state */
extern chan_event_fn *chan_rcvd_ieof;
extern chan_event_fn *chan_write_failed;
extern chan_event_fn *chan_obuf_empty;
extern chan_event_fn *chan_delete_if_full_closed;
void chan_init_iostates(Channel * c);
void chan_init(void);
#endif

64
crypto/openssh/nchan2.ms Normal file
View File

@ -0,0 +1,64 @@
.TL
OpenSSH Channel Close Protocol 2.0 Implementation
.SH
Channel Input State Diagram
.PS
reset
l=1
s=1.2
ellipsewid=s*ellipsewid
boxwid=s*boxwid
ellipseht=s*ellipseht
S1: ellipse "INPUT" "OPEN"
move right 2*l from last ellipse.e
S3: ellipse invis
move down l from last ellipse.s
S4: ellipse "INPUT" "CLOSED"
move down l from 1st ellipse.s
S2: ellipse "INPUT" "WAIT" "DRAIN"
arrow from S1.e to S4.n
box invis "rcvd CLOSE/" "shutdown_read" with .sw at last arrow.c
arrow "ibuf_empty ||" "rcvd CLOSE/" "send EOF" "" from S2.e to S4.w
arrow from S1.s to S2.n
box invis "read_failed/" "shutdown_read" with .e at last arrow.c
ellipse wid .9*ellipsewid ht .9*ellipseht at S4
arrow "start" "" from S1.w+(-0.5,0) to S1.w
.PE
.SH
Channel Output State Diagram
.PS
S1: ellipse "OUTPUT" "OPEN"
move right 2*l from last ellipse.e
S3: ellipse invis
move down l from last ellipse.s
S4: ellipse "OUTPUT" "CLOSED"
move down l from 1st ellipse.s
S2: ellipse "OUTPUT" "WAIT" "DRAIN"
arrow from S1.e to S4.n
box invis "write_failed/" "shutdown_write" with .sw at last arrow.c
arrow "obuf_empty ||" "write_failed/" "shutdown_write" "" from S2.e to S4.w
arrow from S1.s to S2.n
box invis "rcvd EOF ||" "rcvd CLOSE/" "-" with .e at last arrow.c
ellipse wid .9*ellipsewid ht .9*ellipseht at S4
arrow "start" "" from S1.w+(-0.5,0) to S1.w
.PE
.SH
Notes
.PP
The input buffer is filled with data from the socket
(the socket represents the local consumer/producer of the
forwarded channel).
The data is then sent over the INPUT-end (transmit-end) of the channel to the
remote peer.
Data sent by the peer is received on the OUTPUT-end (receive-end),
saved in the output buffer and written to the socket.
.PP
If the local protocol instance has forwarded all data on the
INPUT-end of the channel, it sends an EOF message to the peer.
.PP
A CLOSE message is sent to the peer if
both the INPUT- and the OUTOUT-half of the local
end of the channel are closed.
.PP
The channel can be deallocated by a protocol instance
if a CLOSE message he been both sent and received.

View File

@ -1,21 +1,23 @@
/*
*
*
* packet.c
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Sat Mar 18 02:40:40 1995 ylo
*
*
* This file contains code implementing the packet protocol and communication
* with the other side. This same code is used both on client and server side.
*
*
* SSH2 packet format added by Markus Friedl.
*
*/
#include "includes.h"
RCSID("$Id: packet.c,v 1.22 2000/02/05 10:13:11 markus Exp $");
RCSID("$Id: packet.c,v 1.32 2000/05/04 22:22:43 markus Exp $");
#include "xmalloc.h"
#include "buffer.h"
@ -28,6 +30,23 @@ RCSID("$Id: packet.c,v 1.22 2000/02/05 10:13:11 markus Exp $");
#include "compress.h"
#include "deattack.h"
#include "channels.h"
#include "compat.h"
#include "ssh2.h"
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/hmac.h>
#include "buffer.h"
#include "kex.h"
#include "hmac.h"
#ifdef PACKET_DEBUG
#define DBG(x) x
#else
#define DBG(x)
#endif
/*
* This variable contains the file descriptors used for communicating with
@ -80,19 +99,53 @@ static int initialized = 0;
/* Set to true if the connection is interactive. */
static int interactive_mode = 0;
/* True if SSH2 packet format is used */
int use_ssh2_packet_format = 0;
/* Session key information for Encryption and MAC */
Kex *kex = NULL;
void
packet_set_kex(Kex *k)
{
if( k->mac[MODE_IN ].key == NULL ||
k->enc[MODE_IN ].key == NULL ||
k->enc[MODE_IN ].iv == NULL ||
k->mac[MODE_OUT].key == NULL ||
k->enc[MODE_OUT].key == NULL ||
k->enc[MODE_OUT].iv == NULL)
fatal("bad KEX");
kex = k;
}
void
clear_enc_keys(Enc *enc, int len)
{
memset(enc->iv, 0, len);
memset(enc->key, 0, len);
xfree(enc->iv);
xfree(enc->key);
enc->iv = NULL;
enc->key = NULL;
}
void
packet_set_ssh2_format(void)
{
DBG(debug("use_ssh2_packet_format"));
use_ssh2_packet_format = 1;
}
/*
* Sets the descriptors used for communication. Disables encryption until
* packet_set_encryption_key is called.
*/
void
packet_set_connection(int fd_in, int fd_out)
{
connection_in = fd_in;
connection_out = fd_out;
cipher_type = SSH_CIPHER_NONE;
cipher_set_key(&send_context, SSH_CIPHER_NONE, (unsigned char *) "", 0, 1);
cipher_set_key(&receive_context, SSH_CIPHER_NONE, (unsigned char *) "", 0, 0);
cipher_set_key(&send_context, SSH_CIPHER_NONE, (unsigned char *) "", 0);
cipher_set_key(&receive_context, SSH_CIPHER_NONE, (unsigned char *) "", 0);
if (!initialized) {
initialized = 1;
buffer_init(&input);
@ -224,6 +277,7 @@ packet_get_protocol_flags()
* Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
*/
/*** XXXXX todo: kex means re-init */
void
packet_start_compression(int level)
{
@ -241,7 +295,7 @@ packet_start_compression(int level)
void
packet_encrypt(CipherContext * cc, void *dest, void *src,
unsigned int bytes)
unsigned int bytes)
{
cipher_encrypt(cc, dest, src, bytes);
}
@ -253,7 +307,7 @@ packet_encrypt(CipherContext * cc, void *dest, void *src,
void
packet_decrypt(CipherContext * cc, void *dest, void *src,
unsigned int bytes)
unsigned int bytes)
{
int i;
@ -265,15 +319,11 @@ packet_decrypt(CipherContext * cc, void *dest, void *src,
* (C)1998 CORE-SDI, Buenos Aires Argentina Ariel Futoransky(futo@core-sdi.com)
*/
switch (cc->type) {
case SSH_CIPHER_NONE:
if (cc->type == SSH_CIPHER_NONE || compat20) {
i = DEATTACK_OK;
break;
default:
} else {
i = detect_attack(src, bytes, NULL);
break;
}
if (i == DEATTACK_DETECTED)
packet_disconnect("crc32 compensation attack: network attack detected");
@ -288,17 +338,20 @@ packet_decrypt(CipherContext * cc, void *dest, void *src,
void
packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
int cipher)
int cipher)
{
if (keylen < 20)
fatal("keylen too small: %d", keylen);
/* All other ciphers use the same key in both directions for now. */
cipher_set_key(&receive_context, cipher, key, keylen, 0);
cipher_set_key(&send_context, cipher, key, keylen, 1);
cipher_set_key(&receive_context, cipher, key, keylen);
cipher_set_key(&send_context, cipher, key, keylen);
}
/* Starts constructing a packet to send. */
void
packet_start(int type)
packet_start1(int type)
{
char buf[9];
@ -308,6 +361,29 @@ packet_start(int type)
buffer_append(&outgoing_packet, buf, 9);
}
void
packet_start2(int type)
{
char buf[4+1+1];
buffer_clear(&outgoing_packet);
memset(buf, 0, sizeof buf);
/* buf[0..3] = payload_len; */
/* buf[4] = pad_len; */
buf[5] = type & 0xff;
buffer_append(&outgoing_packet, buf, sizeof buf);
}
void
packet_start(int type)
{
DBG(debug("packet_start[%d]",type));
if (use_ssh2_packet_format)
packet_start2(type);
else
packet_start1(type);
}
/* Appends a character to the packet data. */
void
@ -332,6 +408,18 @@ packet_put_string(const char *buf, unsigned int len)
{
buffer_put_string(&outgoing_packet, buf, len);
}
void
packet_put_cstring(const char *str)
{
buffer_put_string(&outgoing_packet, str, strlen(str));
}
void
packet_put_raw(const char *buf, unsigned int len)
{
buffer_append(&outgoing_packet, buf, len);
}
/* Appends an arbitrary precision integer to packet data. */
@ -340,6 +428,11 @@ packet_put_bignum(BIGNUM * value)
{
buffer_put_bignum(&outgoing_packet, value);
}
void
packet_put_bignum2(BIGNUM * value)
{
buffer_put_bignum2(&outgoing_packet, value);
}
/*
* Finalizes and sends the packet. If the encryption key has been set,
@ -347,7 +440,7 @@ packet_put_bignum(BIGNUM * value)
*/
void
packet_send()
packet_send1()
{
char buf[8], *cp;
int i, padding, len;
@ -372,7 +465,7 @@ packet_send()
/* Compute packet length without padding (add checksum, remove padding). */
len = buffer_len(&outgoing_packet) + 4 - 8;
/* Insert padding. */
/* Insert padding. Initialized to zero in packet_start1() */
padding = 8 - len % 8;
if (cipher_type != SSH_CIPHER_NONE) {
cp = buffer_ptr(&outgoing_packet);
@ -417,6 +510,136 @@ packet_send()
*/
}
/*
* Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
*/
void
packet_send2()
{
unsigned char *macbuf = NULL;
char *cp;
unsigned int packet_length = 0;
unsigned int i, padlen, len;
u_int32_t rand = 0;
static unsigned int seqnr = 0;
int type;
Enc *enc = NULL;
Mac *mac = NULL;
Comp *comp = NULL;
int block_size;
if (kex != NULL) {
enc = &kex->enc[MODE_OUT];
mac = &kex->mac[MODE_OUT];
comp = &kex->comp[MODE_OUT];
}
block_size = enc ? enc->block_size : 8;
cp = buffer_ptr(&outgoing_packet);
type = cp[5] & 0xff;
#ifdef PACKET_DEBUG
fprintf(stderr, "plain: ");
buffer_dump(&outgoing_packet);
#endif
if (comp && comp->enabled) {
len = buffer_len(&outgoing_packet);
/* skip header, compress only payload */
buffer_consume(&outgoing_packet, 5);
buffer_clear(&compression_buffer);
buffer_compress(&outgoing_packet, &compression_buffer);
buffer_clear(&outgoing_packet);
buffer_append(&outgoing_packet, "\0\0\0\0\0", 5);
buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
buffer_len(&compression_buffer));
DBG(debug("compression: raw %d compressed %d", len,
buffer_len(&outgoing_packet)));
}
/* sizeof (packet_len + pad_len + payload) */
len = buffer_len(&outgoing_packet);
/*
* calc size of padding, alloc space, get random data,
* minimum padding is 4 bytes
*/
padlen = block_size - (len % block_size);
if (padlen < 4)
padlen += block_size;
buffer_append_space(&outgoing_packet, &cp, padlen);
if (enc && enc->type != SSH_CIPHER_NONE) {
/* random padding */
for (i = 0; i < padlen; i++) {
if (i % 4 == 0)
rand = arc4random();
cp[i] = rand & 0xff;
rand <<= 8;
}
} else {
/* clear padding */
memset(cp, 0, padlen);
}
/* packet_length includes payload, padding and padding length field */
packet_length = buffer_len(&outgoing_packet) - 4;
cp = buffer_ptr(&outgoing_packet);
PUT_32BIT(cp, packet_length);
cp[4] = padlen & 0xff;
DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen));
/* compute MAC over seqnr and packet(length fields, payload, padding) */
if (mac && mac->enabled) {
macbuf = hmac( mac->md, seqnr,
(unsigned char *) buffer_ptr(&outgoing_packet),
buffer_len(&outgoing_packet),
mac->key, mac->key_len
);
DBG(debug("done calc HMAC out #%d", seqnr));
}
/* encrypt packet and append to output buffer. */
buffer_append_space(&output, &cp, buffer_len(&outgoing_packet));
packet_encrypt(&send_context, cp, buffer_ptr(&outgoing_packet),
buffer_len(&outgoing_packet));
/* append unencrypted MAC */
if (mac && mac->enabled)
buffer_append(&output, (char *)macbuf, mac->mac_len);
#ifdef PACKET_DEBUG
fprintf(stderr, "encrypted: ");
buffer_dump(&output);
#endif
/* increment sequence number for outgoing packets */
if (++seqnr == 0)
log("outgoing seqnr wraps around");
buffer_clear(&outgoing_packet);
if (type == SSH2_MSG_NEWKEYS) {
if (kex==NULL || mac==NULL || enc==NULL || comp==NULL)
fatal("packet_send2: no KEX");
if (mac->md != NULL)
mac->enabled = 1;
DBG(debug("cipher_set_key_iv send_context"));
cipher_set_key_iv(&send_context, enc->type,
enc->key, enc->key_len,
enc->iv, enc->iv_len);
clear_enc_keys(enc, kex->we_need);
if (comp->type != 0 && comp->enabled == 0) {
comp->enabled = 1;
if (! packet_compression)
packet_start_compression(6);
}
}
}
void
packet_send()
{
if (use_ssh2_packet_format)
packet_send2();
else
packet_send1();
DBG(debug("packet_send done"));
}
/*
* Waits until a packet has been received, and returns its type. Note that
* no other data is processed until this returns, so this function should not
@ -429,6 +652,7 @@ packet_read(int *payload_len_ptr)
int type, len;
fd_set set;
char buf[8192];
DBG(debug("packet_read()"));
/* Since we are blocking, ensure that all written packets have been sent. */
packet_write_wait();
@ -437,10 +661,11 @@ packet_read(int *payload_len_ptr)
for (;;) {
/* Try to read a packet from the buffer. */
type = packet_read_poll(payload_len_ptr);
if (type == SSH_SMSG_SUCCESS
if (!use_ssh2_packet_format && (
type == SSH_SMSG_SUCCESS
|| type == SSH_SMSG_FAILURE
|| type == SSH_CMSG_EOF
|| type == SSH_CMSG_EXIT_CONFIRMATION)
|| type == SSH_CMSG_EXIT_CONFIRMATION))
packet_integrity_check(*payload_len_ptr, 0, type);
/* If we got a packet, return it. */
if (type != SSH_MSG_NONE)
@ -482,7 +707,7 @@ packet_read_expect(int *payload_len_ptr, int expected_type)
type = packet_read(payload_len_ptr);
if (type != expected_type)
packet_disconnect("Protocol error: expected packet type %d, got %d",
expected_type, type);
expected_type, type);
}
/* Checks if a full packet is available in the data received so far via
@ -501,15 +726,13 @@ packet_read_expect(int *payload_len_ptr, int expected_type)
*/
int
packet_read_poll(int *payload_len_ptr)
packet_read_poll1(int *payload_len_ptr)
{
unsigned int len, padded_len;
unsigned char *ucp;
char buf[8], *cp, *msg;
char buf[8], *cp;
unsigned int checksum, stored_checksum;
restart:
/* Check if input size is less than minimum packet size. */
if (buffer_len(&input) < 4 + 8)
return SSH_MSG_NONE;
@ -542,7 +765,7 @@ packet_read_poll(int *payload_len_ptr)
/* Compute packet checksum. */
checksum = crc32((unsigned char *) buffer_ptr(&incoming_packet),
buffer_len(&incoming_packet) - 4);
buffer_len(&incoming_packet) - 4);
/* Skip padding. */
buffer_consume(&incoming_packet, 8 - len % 8);
@ -551,7 +774,7 @@ packet_read_poll(int *payload_len_ptr)
if (len != buffer_len(&incoming_packet))
packet_disconnect("packet_read_poll: len %d != buffer_len %d.",
len, buffer_len(&incoming_packet));
len, buffer_len(&incoming_packet));
ucp = (unsigned char *) buffer_ptr(&incoming_packet) + len - 4;
stored_checksum = GET_32BIT(ucp);
@ -565,7 +788,7 @@ packet_read_poll(int *payload_len_ptr)
buffer_uncompress(&incoming_packet, &compression_buffer);
buffer_clear(&incoming_packet);
buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
buffer_len(&compression_buffer));
buffer_len(&compression_buffer));
}
/* Get packet type. */
buffer_get(&incoming_packet, &buf[0], 1);
@ -573,29 +796,208 @@ packet_read_poll(int *payload_len_ptr)
/* Return length of payload (without type field). */
*payload_len_ptr = buffer_len(&incoming_packet);
/* Handle disconnect message. */
if ((unsigned char) buf[0] == SSH_MSG_DISCONNECT) {
msg = packet_get_string(NULL);
log("Received disconnect: %.900s", msg);
xfree(msg);
fatal_cleanup();
}
/* Ignore ignore messages. */
if ((unsigned char) buf[0] == SSH_MSG_IGNORE)
goto restart;
/* Send debug messages as debugging output. */
if ((unsigned char) buf[0] == SSH_MSG_DEBUG) {
msg = packet_get_string(NULL);
debug("Remote: %.900s", msg);
xfree(msg);
goto restart;
}
/* Return type. */
return (unsigned char) buf[0];
}
int
packet_read_poll2(int *payload_len_ptr)
{
unsigned int padlen, need;
unsigned char buf[8], *macbuf;
unsigned char *ucp;
char *cp;
static unsigned int packet_length = 0;
static unsigned int seqnr = 0;
int type;
int maclen, block_size;
Enc *enc = NULL;
Mac *mac = NULL;
Comp *comp = NULL;
if (kex != NULL) {
enc = &kex->enc[MODE_IN];
mac = &kex->mac[MODE_IN];
comp = &kex->comp[MODE_IN];
}
maclen = mac && mac->enabled ? mac->mac_len : 0;
block_size = enc ? enc->block_size : 8;
if (packet_length == 0) {
/*
* check if input size is less than the cipher block size,
* decrypt first block and extract length of incoming packet
*/
if (buffer_len(&input) < block_size)
return SSH_MSG_NONE;
buffer_clear(&incoming_packet);
buffer_append_space(&incoming_packet, &cp, block_size);
packet_decrypt(&receive_context, cp, buffer_ptr(&input),
block_size);
ucp = (unsigned char *) buffer_ptr(&incoming_packet);
packet_length = GET_32BIT(ucp);
if (packet_length < 1 + 4 || packet_length > 256 * 1024) {
buffer_dump(&incoming_packet);
packet_disconnect("Bad packet length %d.", packet_length);
}
DBG(debug("input: packet len %d", packet_length+4));
buffer_consume(&input, block_size);
}
/* we have a partial packet of block_size bytes */
need = 4 + packet_length - block_size;
DBG(debug("partial packet %d, need %d, maclen %d", block_size,
need, maclen));
if (need % block_size != 0)
fatal("padding error: need %d block %d mod %d",
need, block_size, need % block_size);
/*
* check if the entire packet has been received and
* decrypt into incoming_packet
*/
if (buffer_len(&input) < need + maclen)
return SSH_MSG_NONE;
#ifdef PACKET_DEBUG
fprintf(stderr, "read_poll enc/full: ");
buffer_dump(&input);
#endif
buffer_append_space(&incoming_packet, &cp, need);
packet_decrypt(&receive_context, cp, buffer_ptr(&input), need);
buffer_consume(&input, need);
/*
* compute MAC over seqnr and packet,
* increment sequence number for incoming packet
*/
if (mac && mac->enabled) {
macbuf = hmac( mac->md, seqnr,
(unsigned char *) buffer_ptr(&incoming_packet),
buffer_len(&incoming_packet),
mac->key, mac->key_len
);
if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0)
packet_disconnect("Corrupted HMAC on input.");
DBG(debug("HMAC #%d ok", seqnr));
buffer_consume(&input, mac->mac_len);
}
if (++seqnr == 0)
log("incoming seqnr wraps around");
/* get padlen */
cp = buffer_ptr(&incoming_packet) + 4;
padlen = *cp & 0xff;
DBG(debug("input: padlen %d", padlen));
if (padlen < 4)
packet_disconnect("Corrupted padlen %d on input.", padlen);
/* skip packet size + padlen, discard padding */
buffer_consume(&incoming_packet, 4 + 1);
buffer_consume_end(&incoming_packet, padlen);
DBG(debug("input: len before de-compress %d", buffer_len(&incoming_packet)));
if (comp && comp->enabled) {
buffer_clear(&compression_buffer);
buffer_uncompress(&incoming_packet, &compression_buffer);
buffer_clear(&incoming_packet);
buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
buffer_len(&compression_buffer));
DBG(debug("input: len after de-compress %d", buffer_len(&incoming_packet)));
}
/*
* get packet type, implies consume.
* return length of payload (without type field)
*/
buffer_get(&incoming_packet, (char *)&buf[0], 1);
*payload_len_ptr = buffer_len(&incoming_packet);
/* reset for next packet */
packet_length = 0;
/* extract packet type */
type = (unsigned char)buf[0];
if (type == SSH2_MSG_NEWKEYS) {
if (kex==NULL || mac==NULL || enc==NULL || comp==NULL)
fatal("packet_read_poll2: no KEX");
if (mac->md != NULL)
mac->enabled = 1;
DBG(debug("cipher_set_key_iv receive_context"));
cipher_set_key_iv(&receive_context, enc->type,
enc->key, enc->key_len,
enc->iv, enc->iv_len);
clear_enc_keys(enc, kex->we_need);
if (comp->type != 0 && comp->enabled == 0) {
comp->enabled = 1;
if (! packet_compression)
packet_start_compression(6);
}
}
#ifdef PACKET_DEBUG
fprintf(stderr, "read/plain[%d]:\r\n",type);
buffer_dump(&incoming_packet);
#endif
return (unsigned char)type;
}
int
packet_read_poll(int *payload_len_ptr)
{
char *msg;
for (;;) {
int type = use_ssh2_packet_format ?
packet_read_poll2(payload_len_ptr):
packet_read_poll1(payload_len_ptr);
if(compat20) {
int reason;
if (type != 0)
DBG(debug("received packet type %d", type));
switch(type) {
case SSH2_MSG_IGNORE:
break;
case SSH2_MSG_DEBUG:
packet_get_char();
msg = packet_get_string(NULL);
debug("Remote: %.900s", msg);
xfree(msg);
msg = packet_get_string(NULL);
xfree(msg);
break;
case SSH2_MSG_DISCONNECT:
reason = packet_get_int();
msg = packet_get_string(NULL);
log("Received disconnect: %d: %.900s", reason, msg);
xfree(msg);
fatal_cleanup();
break;
default:
return type;
break;
}
} else {
switch(type) {
case SSH_MSG_IGNORE:
break;
case SSH_MSG_DEBUG:
msg = packet_get_string(NULL);
debug("Remote: %.900s", msg);
xfree(msg);
break;
case SSH_MSG_DISCONNECT:
msg = packet_get_string(NULL);
log("Received disconnect: %.900s", msg);
fatal_cleanup();
xfree(msg);
break;
default:
if (type != 0)
DBG(debug("received packet type %d", type));
return type;
break;
}
}
}
}
/*
* Buffers the given amount of input characters. This is intended to be used
* together with packet_read_poll.
@ -636,6 +1038,27 @@ packet_get_bignum(BIGNUM * value, int *length_ptr)
*length_ptr = buffer_get_bignum(&incoming_packet, value);
}
void
packet_get_bignum2(BIGNUM * value, int *length_ptr)
{
*length_ptr = buffer_get_bignum2(&incoming_packet, value);
}
char *
packet_get_raw(int *length_ptr)
{
int bytes = buffer_len(&incoming_packet);
if (length_ptr != NULL)
*length_ptr = bytes;
return buffer_ptr(&incoming_packet);
}
int
packet_remaining(void)
{
return buffer_len(&incoming_packet);
}
/*
* Returns a string from the packet data. The string is allocated using
* xmalloc; it is the responsibility of the calling program to free it when
@ -668,8 +1091,15 @@ packet_send_debug(const char *fmt,...)
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
packet_start(SSH_MSG_DEBUG);
packet_put_string(buf, strlen(buf));
if (compat20) {
packet_start(SSH2_MSG_DEBUG);
packet_put_char(0); /* bool: always display */
packet_put_cstring(buf);
packet_put_cstring("");
} else {
packet_start(SSH_MSG_DEBUG);
packet_put_cstring(buf);
}
packet_send();
packet_write_wait();
}
@ -700,8 +1130,15 @@ packet_disconnect(const char *fmt,...)
va_end(args);
/* Send the disconnect message to the other side, and wait for it to get sent. */
packet_start(SSH_MSG_DISCONNECT);
packet_put_string(buf, strlen(buf));
if (compat20) {
packet_start(SSH2_MSG_DISCONNECT);
packet_put_int(SSH2_DISCONNECT_PROTOCOL_ERROR);
packet_put_cstring(buf);
packet_put_cstring("");
} else {
packet_start(SSH_MSG_DISCONNECT);
packet_put_string(buf, strlen(buf));
}
packet_send();
packet_write_wait();
@ -832,7 +1269,8 @@ packet_set_maxsize(int s)
{
static int called = 0;
if (called) {
log("packet_set_maxsize: called twice: old %d new %d", max_packet_size, s);
log("packet_set_maxsize: called twice: old %d new %d",
max_packet_size, s);
return -1;
}
if (s < 4 * 1024 || s > 1024 * 1024) {

View File

@ -1,19 +1,19 @@
/*
*
*
* pty.h
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Fri Mar 17 05:03:28 1995 ylo
*
*
* Functions for allocating a pseudo-terminal and making it the controlling
* tty.
*/
/* RCSID("$Id: pty.h,v 1.5 2000/02/15 16:52:58 markus Exp $"); */
/* RCSID("$Id: pty.h,v 1.6 2000/04/14 10:30:32 markus Exp $"); */
#ifndef PTY_H
#define PTY_H
@ -39,7 +39,7 @@ void pty_release(const char *ttyname);
void pty_make_controlling_tty(int *ttyfd, const char *ttyname);
/* Changes the window size associated with the pty. */
void
void
pty_change_window_size(int ptyfd, int row, int col,
int xpixel, int ypixel);

View File

@ -1,109 +1,15 @@
/*
* radix.c
*
* base-64 encoding pinched from lynx2-7-2, who pinched it from rpem.
* Originally written by Mark Riordan 12 August 1990 and 17 Feb 1991
* and placed in the public domain.
*
*
* Dug Song <dugsong@UMICH.EDU>
*/
#include "includes.h"
#include "uuencode.h"
#ifdef AFS
#include <krb.h>
char six2pr[64] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};
unsigned char pr2six[256];
int
uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded)
{
/* ENC is the basic 1 character encoding function to make a char printing */
#define ENC(c) six2pr[c]
register char *outptr = bufcoded;
unsigned int i;
for (i = 0; i < nbytes; i += 3) {
*(outptr++) = ENC(*bufin >> 2); /* c1 */
*(outptr++) = ENC(((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)); /* c2 */
*(outptr++) = ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03)); /* c3 */
*(outptr++) = ENC(bufin[2] & 077); /* c4 */
bufin += 3;
}
if (i == nbytes + 1) {
outptr[-1] = '=';
} else if (i == nbytes + 2) {
outptr[-1] = '=';
outptr[-2] = '=';
}
*outptr = '\0';
return (outptr - bufcoded);
}
int
uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize)
{
/* single character decode */
#define DEC(c) pr2six[(unsigned char)c]
#define MAXVAL 63
static int first = 1;
int nbytesdecoded, j;
const char *bufin = bufcoded;
register unsigned char *bufout = bufplain;
register int nprbytes;
/* If this is the first call, initialize the mapping table. */
if (first) {
first = 0;
for (j = 0; j < 256; j++)
pr2six[j] = MAXVAL + 1;
for (j = 0; j < 64; j++)
pr2six[(unsigned char) six2pr[j]] = (unsigned char) j;
}
/* Strip leading whitespace. */
while (*bufcoded == ' ' || *bufcoded == '\t')
bufcoded++;
/*
* Figure out how many characters are in the input buffer. If this
* would decode into more bytes than would fit into the output
* buffer, adjust the number of input bytes downwards.
*/
bufin = bufcoded;
while (DEC(*(bufin++)) <= MAXVAL);
nprbytes = bufin - bufcoded - 1;
nbytesdecoded = ((nprbytes + 3) / 4) * 3;
if (nbytesdecoded > outbufsize)
nprbytes = (outbufsize * 4) / 3;
bufin = bufcoded;
while (nprbytes > 0) {
*(bufout++) = (unsigned char) (DEC(*bufin) << 2 | DEC(bufin[1]) >> 4);
*(bufout++) = (unsigned char) (DEC(bufin[1]) << 4 | DEC(bufin[2]) >> 2);
*(bufout++) = (unsigned char) (DEC(bufin[2]) << 6 | DEC(bufin[3]));
bufin += 4;
nprbytes -= 4;
}
if (nprbytes & 03) {
if (DEC(bufin[-2]) > MAXVAL)
nbytesdecoded -= 2;
else
nbytesdecoded -= 1;
}
return (nbytesdecoded);
}
typedef unsigned char my_u_char;
typedef unsigned int my_u_int32_t;
typedef unsigned short my_u_short;
@ -162,8 +68,8 @@ typedef unsigned short my_u_short;
}
int
creds_to_radix(CREDENTIALS *creds, unsigned char *buf)
int
creds_to_radix(CREDENTIALS *creds, unsigned char *buf, size_t buflen)
{
char *p, *s;
int len;
@ -213,10 +119,10 @@ creds_to_radix(CREDENTIALS *creds, unsigned char *buf)
p += creds->ticket_st.length;
len = p - temp;
return (uuencode((unsigned char *)temp, len, (char *)buf));
return (uuencode((unsigned char *)temp, len, (char *)buf, buflen));
}
int
int
radix_to_creds(const char *buf, CREDENTIALS *creds)
{
@ -225,7 +131,8 @@ radix_to_creds(const char *buf, CREDENTIALS *creds)
char version;
char temp[2048];
if (!(len = uudecode(buf, (unsigned char *)temp, sizeof(temp))))
len = uudecode(buf, (unsigned char *)temp, sizeof(temp));
if (len < 0)
return 0;
p = temp;

View File

@ -32,7 +32,7 @@
*/
#include "includes.h"
RCSID("$Id: readpass.c,v 1.9 2000/01/21 21:16:00 deraadt Exp $");
RCSID("$Id: readpass.c,v 1.10 2000/04/14 10:30:32 markus Exp $");
#include "xmalloc.h"
#include "ssh.h"
@ -58,7 +58,7 @@ read_passphrase(const char *prompt, int from_stdin)
sigset_t oset, nset;
struct sigaction sa, osa;
int input, output, echo = 0;
if (from_stdin) {
input = STDIN_FILENO;
output = STDERR_FILENO;

View File

@ -9,7 +9,7 @@
.\"
.\" Created: Sun May 7 00:14:37 1995 ylo
.\"
.\" $Id: scp.1,v 1.6 2000/03/23 21:10:09 aaron Exp $
.\" $Id: scp.1,v 1.7 2000/04/12 21:47:50 aaron Exp $
.\"
.Dd September 25, 1999
.Dt SCP 1
@ -36,7 +36,7 @@
.Ar host2 No :
.Oc Ar file2
.Sm on
.Sh DESCRIPTION
.Sh DESCRIPTION
.Nm
copies files between hosts on a network.
It uses
@ -74,7 +74,7 @@ Recursively copy entire directories.
Verbose mode.
Causes
.Nm
and
and
.Xr ssh 1
to print debugging messages about their progress.
This is helpful in

View File

@ -1,13 +1,13 @@
/*
*
*
* scp - secure remote copy. This is basically patched BSD rcp which uses ssh
* to do the data transfer (instead of using rcmd).
*
*
* NOTE: This version should NOT be suid root. (This uses ssh to do the transfer
* and ssh has the necessary privileges.)
*
*
* 1995 Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi>
*
*
*/
/*
@ -45,7 +45,7 @@
*/
#include "includes.h"
RCSID("$Id: scp.c,v 1.26 2000/03/16 20:56:14 markus Exp $");
RCSID("$Id: scp.c,v 1.30 2000/05/02 18:21:48 deraadt Exp $");
#include "ssh.h"
#include "xmalloc.h"
@ -109,7 +109,7 @@ char *port = NULL;
* assigns the input and output file descriptors on success.
*/
int
int
do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
{
int pin[2], pout[2], reserved[2];
@ -194,7 +194,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
return 0;
}
void
void
fatal(const char *fmt,...)
{
va_list ap;
@ -257,10 +257,10 @@ main(argc, argv)
switch (ch) {
/* User-visible flags. */
case '4':
IPv4 = 1;
IPv4 = 1;
break;
case '6':
IPv6 = 1;
IPv6 = 1;
break;
case 'p':
pflag = 1;
@ -543,7 +543,7 @@ syserr: run_err("%s: %s", name, strerror(errno));
(void) sprintf(buf, "T%lu 0 %lu 0\n",
(unsigned long) stb.st_mtime,
(unsigned long) stb.st_atime);
(void) write(remout, buf, strlen(buf));
(void) atomicio(write, remout, buf, strlen(buf));
if (response() < 0)
goto next;
}
@ -556,7 +556,7 @@ syserr: run_err("%s: %s", name, strerror(errno));
fprintf(stderr, "Sending file modes: %s", buf);
fflush(stderr);
}
(void) write(remout, buf, strlen(buf));
(void) atomicio(write, remout, buf, strlen(buf));
if (response() < 0)
goto next;
if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) {
@ -573,14 +573,14 @@ next: (void) close(fd);
if (i + amt > stb.st_size)
amt = stb.st_size - i;
if (!haderr) {
result = read(fd, bp->buf, amt);
result = atomicio(read, fd, bp->buf, amt);
if (result != amt)
haderr = result >= 0 ? EIO : errno;
}
if (haderr)
(void) write(remout, bp->buf, amt);
(void) atomicio(write, remout, bp->buf, amt);
else {
result = write(remout, bp->buf, amt);
result = atomicio(write, remout, bp->buf, amt);
if (result != amt)
haderr = result >= 0 ? EIO : errno;
statbytes += result;
@ -592,7 +592,7 @@ next: (void) close(fd);
if (close(fd) < 0 && !haderr)
haderr = errno;
if (!haderr)
(void) write(remout, "", 1);
(void) atomicio(write, remout, "", 1);
else
run_err("%s: %s", name, strerror(haderr));
(void) response();
@ -621,7 +621,7 @@ rsource(name, statp)
(void) sprintf(path, "T%lu 0 %lu 0\n",
(unsigned long) statp->st_mtime,
(unsigned long) statp->st_atime);
(void) write(remout, path, strlen(path));
(void) atomicio(write, remout, path, strlen(path));
if (response() < 0) {
closedir(dirp);
return;
@ -632,7 +632,7 @@ rsource(name, statp)
0, last);
if (verbose_mode)
fprintf(stderr, "Entering directory: %s", path);
(void) write(remout, path, strlen(path));
(void) atomicio(write, remout, path, strlen(path));
if (response() < 0) {
closedir(dirp);
return;
@ -651,7 +651,7 @@ rsource(name, statp)
source(1, vect);
}
(void) closedir(dirp);
(void) write(remout, "E\n", 2);
(void) atomicio(write, remout, "E\n", 2);
(void) response();
}
@ -687,17 +687,17 @@ sink(argc, argv)
if (targetshouldbedirectory)
verifydir(targ);
(void) write(remout, "", 1);
(void) atomicio(write, remout, "", 1);
if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
targisdir = 1;
for (first = 1;; first = 0) {
cp = buf;
if (read(remin, cp, 1) <= 0)
if (atomicio(read, remin, cp, 1) <= 0)
return;
if (*cp++ == '\n')
SCREWUP("unexpected <newline>");
do {
if (read(remin, &ch, sizeof(ch)) != sizeof(ch))
if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
SCREWUP("lost connection");
*cp++ = ch;
} while (cp < &buf[sizeof(buf) - 1] && ch != '\n');
@ -705,7 +705,7 @@ sink(argc, argv)
if (buf[0] == '\01' || buf[0] == '\02') {
if (iamremote == 0)
(void) write(STDERR_FILENO,
(void) atomicio(write, STDERR_FILENO,
buf + 1, strlen(buf + 1));
if (buf[0] == '\02')
exit(1);
@ -713,7 +713,7 @@ sink(argc, argv)
continue;
}
if (buf[0] == 'E') {
(void) write(remout, "", 1);
(void) atomicio(write, remout, "", 1);
return;
}
if (ch == '\n')
@ -737,7 +737,7 @@ sink(argc, argv)
getnum(dummy_usec);
if (*cp++ != '\0')
SCREWUP("atime.usec not delimited");
(void) write(remout, "", 1);
(void) atomicio(write, remout, "", 1);
continue;
}
if (*cp != 'C' && *cp != 'D') {
@ -816,7 +816,7 @@ sink(argc, argv)
bad: run_err("%s: %s", np, strerror(errno));
continue;
}
(void) write(remout, "", 1);
(void) atomicio(write, remout, "", 1);
if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) {
(void) close(ofd);
continue;
@ -835,7 +835,7 @@ bad: run_err("%s: %s", np, strerror(errno));
amt = size - i;
count += amt;
do {
j = read(remin, cp, amt);
j = atomicio(read, remin, cp, amt);
if (j <= 0) {
run_err("%s", j ? strerror(errno) :
"dropped connection");
@ -848,7 +848,7 @@ bad: run_err("%s: %s", np, strerror(errno));
if (count == bp->cnt) {
/* Keep reading so we stay sync'd up. */
if (wrerr == NO) {
j = write(ofd, bp->buf, count);
j = atomicio(write, ofd, bp->buf, count);
if (j != count) {
wrerr = YES;
wrerrno = j >= 0 ? EIO : errno;
@ -861,7 +861,7 @@ bad: run_err("%s: %s", np, strerror(errno));
if (showprogress)
progressmeter(1);
if (count != 0 && wrerr == NO &&
(j = write(ofd, bp->buf, count)) != count) {
(j = atomicio(write, ofd, bp->buf, count)) != count) {
wrerr = YES;
wrerrno = j >= 0 ? EIO : errno;
}
@ -897,7 +897,7 @@ bad: run_err("%s: %s", np, strerror(errno));
run_err("%s: %s", np, strerror(wrerrno));
break;
case NO:
(void) write(remout, "", 1);
(void) atomicio(write, remout, "", 1);
break;
case DISPLAYED:
break;
@ -913,7 +913,7 @@ response()
{
char ch, *cp, resp, rbuf[2048];
if (read(remin, &resp, sizeof(resp)) != sizeof(resp))
if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp))
lostconn(0);
cp = rbuf;
@ -926,13 +926,13 @@ response()
case 1: /* error, followed by error msg */
case 2: /* fatal error, "" */
do {
if (read(remin, &ch, sizeof(ch)) != sizeof(ch))
if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
lostconn(0);
*cp++ = ch;
} while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n');
if (!iamremote)
(void) write(STDERR_FILENO, rbuf, cp - rbuf);
(void) atomicio(write, STDERR_FILENO, rbuf, cp - rbuf);
++errs;
if (resp == 1)
return (-1);
@ -1006,7 +1006,7 @@ run_err(const char *fmt,...)
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: scp.c,v 1.26 2000/03/16 20:56:14 markus Exp $
* $Id: scp.c,v 1.30 2000/05/02 18:21:48 deraadt Exp $
*/
char *
@ -1209,7 +1209,12 @@ progressmeter(int flag)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
" - stalled -");
} else {
remaining = (int) (totalbytes / (statbytes / elapsed) - elapsed);
if (flag != 1)
remaining =
(int)(totalbytes / (statbytes / elapsed) - elapsed);
else
remaining = elapsed;
i = remaining / 3600;
if (i)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
@ -1219,7 +1224,8 @@ progressmeter(int flag)
" ");
i = remaining % 3600;
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
"%02d:%02d ETA", i / 60, i % 60);
"%02d:%02d%s", i / 60, i % 60,
(flag != 1) ? " ETA" : " ");
}
atomicio(write, fileno(stdout), buf, strlen(buf));
@ -1228,7 +1234,7 @@ progressmeter(int flag)
alarmtimer(1);
} else if (flag == 1) {
alarmtimer(0);
write(fileno(stdout), "\n", 1);
atomicio(write, fileno(stdout), "\n", 1);
statbytes = 0;
}
}

View File

@ -5,6 +5,10 @@
* Created: Sun Sep 10 00:30:37 1995 ylo
* 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 "xmalloc.h"
@ -13,6 +17,12 @@
#include "buffer.h"
#include "servconf.h"
#include "pty.h"
#include "channels.h"
#include "compat.h"
#include "ssh2.h"
#include "session.h"
#include "dispatch.h"
static Buffer stdin_buffer; /* Buffer for stdin data. */
static Buffer stdout_buffer; /* Buffer for stdout data. */
@ -38,15 +48,18 @@ static int max_fd; /* Max file descriptor number for select(). */
* will exit after that, as soon as forwarded connections have terminated.
*/
static int child_pid; /* Pid of the child. */
static pid_t child_pid; /* Pid of the child. */
static volatile int child_terminated; /* The child has terminated. */
static volatile int child_wait_status; /* Status from wait(). */
void
void server_init_dispatch(void);
void
sigchld_handler(int sig)
{
int save_errno = errno;
int wait_pid;
pid_t wait_pid;
debug("Received SIGCHLD.");
wait_pid = wait((int *) &child_wait_status);
if (wait_pid != -1) {
@ -60,110 +73,21 @@ sigchld_handler(int sig)
signal(SIGCHLD, sigchld_handler);
errno = save_errno;
}
/*
* Process any buffered packets that have been received from the client.
*/
void
process_buffered_input_packets()
void
sigchld_handler2(int sig)
{
int type;
char *data;
unsigned int data_len;
int row, col, xpixel, ypixel;
int payload_len;
/* Process buffered packets from the client. */
while ((type = packet_read_poll(&payload_len)) != SSH_MSG_NONE) {
switch (type) {
case SSH_CMSG_STDIN_DATA:
/* Stdin data from the client. Append it to the buffer. */
/* Ignore any data if the client has closed stdin. */
if (fdin == -1)
break;
data = packet_get_string(&data_len);
packet_integrity_check(payload_len, (4 + data_len), type);
buffer_append(&stdin_buffer, data, data_len);
memset(data, 0, data_len);
xfree(data);
break;
case SSH_CMSG_EOF:
/*
* Eof from the client. The stdin descriptor to the
* program will be closed when all buffered data has
* drained.
*/
debug("EOF received for stdin.");
packet_integrity_check(payload_len, 0, type);
stdin_eof = 1;
break;
case SSH_CMSG_WINDOW_SIZE:
debug("Window change received.");
packet_integrity_check(payload_len, 4 * 4, type);
row = packet_get_int();
col = packet_get_int();
xpixel = packet_get_int();
ypixel = packet_get_int();
if (fdin != -1)
pty_change_window_size(fdin, row, col, xpixel, ypixel);
break;
case SSH_MSG_PORT_OPEN:
debug("Received port open request.");
channel_input_port_open(payload_len);
break;
case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
debug("Received channel open confirmation.");
packet_integrity_check(payload_len, 4 + 4, type);
channel_input_open_confirmation();
break;
case SSH_MSG_CHANNEL_OPEN_FAILURE:
debug("Received channel open failure.");
packet_integrity_check(payload_len, 4, type);
channel_input_open_failure();
break;
case SSH_MSG_CHANNEL_DATA:
channel_input_data(payload_len);
break;
case SSH_MSG_CHANNEL_CLOSE:
debug("Received channel close.");
packet_integrity_check(payload_len, 4, type);
channel_input_close();
break;
case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION:
debug("Received channel close confirmation.");
packet_integrity_check(payload_len, 4, type);
channel_input_close_confirmation();
break;
default:
/*
* In this phase, any unexpected messages cause a
* protocol error. This is to ease debugging; also,
* since no confirmations are sent messages,
* unprocessed unknown messages could cause strange
* problems. Any compatible protocol extensions must
* be negotiated before entering the interactive
* session.
*/
packet_disconnect("Protocol error during session: type %d",
type);
}
}
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
* to the client.
*/
void
void
make_packets_from_stderr_data()
{
int len;
@ -192,7 +116,7 @@ make_packets_from_stderr_data()
* Make packets from buffered stdout data, and buffer it for sending to the
* client.
*/
void
void
make_packets_from_stdout_data()
{
int len;
@ -223,7 +147,7 @@ make_packets_from_stdout_data()
* have data or can accept data. Optionally, a maximum time can be specified
* for the duration of the wait (0 = infinite).
*/
void
void
wait_until_can_do_something(fd_set * readset, fd_set * writeset,
unsigned int max_time_milliseconds)
{
@ -240,15 +164,21 @@ wait_until_can_do_something(fd_set * readset, fd_set * writeset,
* Read packets from the client unless we have too much buffered
* stdin or channel data.
*/
if (buffer_len(&stdin_buffer) < 4096 &&
channel_not_very_much_buffered_data())
FD_SET(connection_in, readset);
if (compat20) {
/* wrong: bad condition XXX */
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
* 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)
FD_SET(fdout, readset);
if (!fderr_eof)
@ -268,7 +198,7 @@ wait_until_can_do_something(fd_set * readset, fd_set * writeset,
/* If we have buffered data, try to write some of that data to the
program. */
if (fdin != -1 && buffer_len(&stdin_buffer) > 0)
if (!compat20 && fdin != -1 && buffer_len(&stdin_buffer) > 0)
FD_SET(fdin, writeset);
/* Update the maximum descriptor number if appropriate. */
@ -290,6 +220,8 @@ wait_until_can_do_something(fd_set * readset, fd_set * writeset,
tv.tv_usec = 1000 * (max_time_milliseconds % 1000);
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. */
ret = select(max_fd + 1, readset, writeset, NULL, tvp);
@ -306,7 +238,7 @@ wait_until_can_do_something(fd_set * readset, fd_set * writeset,
* Processes input from the client and the program. Input data is stored
* in buffers and processed later.
*/
void
void
process_input(fd_set * readset)
{
int len;
@ -333,6 +265,9 @@ process_input(fd_set * readset)
/* Buffer any received data. */
packet_process_incoming(buf, len);
}
if (compat20)
return;
/* Read and buffer any available stdout data from the program. */
if (!fdout_eof && FD_ISSET(fdout, readset)) {
len = read(fdout, buf, sizeof(buf));
@ -356,20 +291,20 @@ process_input(fd_set * readset)
/*
* Sends data from internal buffers to client program stdin.
*/
void
void
process_output(fd_set * writeset)
{
int len;
/* 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),
buffer_len(&stdin_buffer));
if (len <= 0) {
#ifdef USE_PIPES
close(fdin);
#else
if (fdout == -1)
if (fdin != fdout)
close(fdin);
else
shutdown(fdin, SHUT_WR); /* We will no longer send. */
@ -391,7 +326,7 @@ process_output(fd_set * writeset)
* Wait until all buffered output has been sent to the client.
* This is used when the program terminates.
*/
void
void
drain_output()
{
/* Send any buffered stdout data to the client. */
@ -416,6 +351,12 @@ drain_output()
packet_write_wait();
}
void
process_buffered_input_packets()
{
dispatch_run(DISPATCH_NONBLOCK, NULL);
}
/*
* Performs the interactive session. This handles data transmission between
* the client and the program. Note that the notion of stdin, stdout, and
@ -423,10 +364,11 @@ drain_output()
* stdin (of the child program), and reads from stdout and stderr (of the
* child program).
*/
void
server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
void
server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
{
int wait_status, wait_pid; /* Status and pid returned by wait(). */
int wait_status; /* Status returned by wait(). */
pid_t wait_pid; /* pid returned by wait(). */
int waiting_termination = 0; /* Have displayed waiting close message. */
unsigned int max_time_milliseconds;
unsigned int previous_stdout_buffer_bytes;
@ -480,6 +422,8 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
if (fderr == -1)
fderr_eof = 1;
server_init_dispatch();
/* Main loop of the server for the interactive session mode. */
for (;;) {
fd_set readset, writeset;
@ -495,7 +439,7 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
#ifdef USE_PIPES
close(fdin);
#else
if (fdout == -1)
if (fdin != fdout)
close(fdin);
else
shutdown(fdin, SHUT_WR); /* We will no longer send. */
@ -536,7 +480,7 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
if (fdout_eof && fderr_eof && !packet_have_data_to_write() &&
buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) {
if (!channel_still_open())
goto quit;
break;
if (!waiting_termination) {
const char *s = "Waiting for forwarded connections to terminate...\r\n";
char *cp;
@ -563,7 +507,6 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
process_output(&writeset);
}
quit:
/* Cleanup and termination code. */
/* Wait until all output has been sent to the client. */
@ -649,3 +592,233 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
packet_disconnect("wait returned status %04x.", wait_status);
/* 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
server_input_stdin_data(int type, int plen)
{
char *data;
unsigned int data_len;
/* Stdin data from the client. Append it to the buffer. */
/* Ignore any data if the client has closed stdin. */
if (fdin == -1)
return;
data = packet_get_string(&data_len);
packet_integrity_check(plen, (4 + data_len), type);
buffer_append(&stdin_buffer, data, data_len);
memset(data, 0, data_len);
xfree(data);
}
void
server_input_eof(int type, int plen)
{
/*
* Eof from the client. The stdin descriptor to the
* program will be closed when all buffered data has
* drained.
*/
debug("EOF received for stdin.");
packet_integrity_check(plen, 0, type);
stdin_eof = 1;
}
void
server_input_window_size(int type, int plen)
{
int row = packet_get_int();
int col = packet_get_int();
int xpixel = packet_get_int();
int ypixel = packet_get_int();
debug("Window change received.");
packet_integrity_check(plen, 4 * 4, type);
if (fdin != -1)
pty_change_window_size(fdin, row, col, xpixel, ypixel);
}
int
input_direct_tcpip(void)
{
int sock;
char *target, *originator;
int target_port, originator_port;
target = packet_get_string(NULL);
target_port = packet_get_int();
originator = packet_get_string(NULL);
originator_port = packet_get_int();
packet_done();
/* XXX check permission */
sock = channel_connect_to(target, target_port);
xfree(target);
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();
debug("channel_input_open: ctype %s rchan %d win %d max %d",
ctype, rchan, rwindow, rmaxpack);
if (strcmp(ctype, "session") == 0) {
debug("open session");
packet_done();
/*
* 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
server_init_dispatch_13()
{
debug("server_init_dispatch_13");
dispatch_init(NULL);
dispatch_set(SSH_CMSG_EOF, &server_input_eof);
dispatch_set(SSH_CMSG_STDIN_DATA, &server_input_stdin_data);
dispatch_set(SSH_CMSG_WINDOW_SIZE, &server_input_window_size);
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close);
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation);
dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data);
dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
}
void
server_init_dispatch_15()
{
server_init_dispatch_13();
debug("server_init_dispatch_15");
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof);
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose);
}
void
server_init_dispatch()
{
if (compat20)
server_init_dispatch_20();
else if (compat13)
server_init_dispatch_13();
else
server_init_dispatch_15();
}

1516
crypto/openssh/session.c Normal file

File diff suppressed because it is too large Load Diff

14
crypto/openssh/session.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef SESSION_H
#define SESSION_H
/* SSH1 */
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

View File

@ -9,28 +9,28 @@
.\"
.\" Created: Sat Apr 22 23:55:14 1995 ylo
.\"
.\" $Id: ssh-add.1,v 1.11 2000/03/23 21:11:38 aaron Exp $
.\" $Id: ssh-add.1,v 1.13 2000/05/03 18:04:38 markus Exp $
.\"
.Dd September 25, 1999
.Dt SSH-ADD 1
.Os
.Sh NAME
.Nm ssh-add
.Nd adds identities for the authentication agent
.Nd adds RSA identities for the authentication agent
.Sh SYNOPSIS
.Nm ssh-add
.Op Fl lLdD
.Op Ar
.Sh DESCRIPTION
.Sh DESCRIPTION
.Nm
adds identities to the authentication agent,
adds RSA identities to the authentication agent,
.Xr ssh-agent 1 .
When run without arguments, it adds the file
.Pa $HOME/.ssh/identity .
Alternative file names can be given on the command line.
If any file requires a passphrase,
.Nm
asks for the passphrase from the user.
asks for the passphrase from the user.
The Passphrase it is read from the user's tty.
.Pp
The authentication agent must be running and must be an ancestor of
@ -108,7 +108,7 @@ external libraries.
.It
has been updated to support ssh protocol 1.5.
.It
contains added support for
contains added support for
.Xr kerberos 8
authentication and ticket passing.
.It

View File

@ -7,30 +7,35 @@
*/
#include "includes.h"
RCSID("$Id: ssh-add.c,v 1.15 1999/12/02 20:05:40 markus Exp $");
RCSID("$Id: ssh-add.c,v 1.16 2000/04/26 20:56:29 markus Exp $");
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include "rsa.h"
#include "ssh.h"
#include "xmalloc.h"
#include "authfd.h"
#include "fingerprint.h"
#include "key.h"
#include "authfile.h"
void
delete_file(AuthenticationConnection *ac, const char *filename)
{
RSA *key;
Key *public;
char *comment;
key = RSA_new();
if (!load_public_key(filename, key, &comment)) {
public = key_new(KEY_RSA);
if (!load_public_key(filename, public, &comment)) {
printf("Bad key file %s: %s\n", filename, strerror(errno));
return;
}
if (ssh_remove_identity(ac, key))
if (ssh_remove_identity(ac, public->rsa))
fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
else
fprintf(stderr, "Could not remove identity: %s\n", filename);
RSA_free(key);
key_free(public);
xfree(comment);
}
@ -85,20 +90,19 @@ ssh_askpass(char *askpass, char *msg)
void
add_file(AuthenticationConnection *ac, const char *filename)
{
RSA *key;
RSA *public_key;
Key *public;
Key *private;
char *saved_comment, *comment, *askpass = NULL;
char buf[1024], msg[1024];
int success;
int interactive = isatty(STDIN_FILENO);
key = RSA_new();
public_key = RSA_new();
if (!load_public_key(filename, public_key, &saved_comment)) {
public = key_new(KEY_RSA);
if (!load_public_key(filename, public, &saved_comment)) {
printf("Bad key file %s: %s\n", filename, strerror(errno));
return;
}
RSA_free(public_key);
key_free(public);
if (!interactive && getenv("DISPLAY")) {
if (getenv(SSH_ASKPASS_ENV))
@ -108,7 +112,8 @@ add_file(AuthenticationConnection *ac, const char *filename)
}
/* At first, try empty passphrase */
success = load_private_key(filename, "", key, &comment);
private = key_new(KEY_RSA);
success = load_private_key(filename, "", private, &comment);
if (!success) {
printf("Need passphrase for %.200s\n", filename);
if (!interactive && askpass == NULL) {
@ -129,7 +134,7 @@ add_file(AuthenticationConnection *ac, const char *filename)
xfree(saved_comment);
return;
}
success = load_private_key(filename, pass, key, &comment);
success = load_private_key(filename, pass, private, &comment);
memset(pass, 0, strlen(pass));
xfree(pass);
if (success)
@ -139,11 +144,11 @@ add_file(AuthenticationConnection *ac, const char *filename)
}
xfree(saved_comment);
if (ssh_add_identity(ac, key, comment))
if (ssh_add_identity(ac, private->rsa, comment))
fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
else
fprintf(stderr, "Could not add identity: %s\n", filename);
RSA_free(key);
key_free(private);
xfree(comment);
}

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: ssh-agent.1,v 1.10 2000/03/23 21:10:10 aaron Exp $
.\" $OpenBSD: ssh-agent.1,v 1.12 2000/05/03 18:04:39 markus Exp $
.\"
.\" -*- nroff -*-
.\"
@ -18,16 +18,16 @@
.Nm ssh-agent
.Nd authentication agent
.Sh SYNOPSIS
.Nm ssh-agent
.Nm ssh-agent
.Op Fl c Li | Fl s
.Op Fl k
.Oo
.Ar command
.Op Ar args ...
.Oc
.Sh DESCRIPTION
.Sh DESCRIPTION
.Nm
is a program to hold authentication private keys.
is a program to hold private keys used for RSA authentication.
The idea is that
.Nm
is started in the beginning of an X-session or a login session, and
@ -64,12 +64,12 @@ When the command dies, so does the agent.
The agent initially does not have any private keys.
Keys are added using
.Xr ssh-add 1 .
When executed without arguments,
When executed without arguments,
.Xr ssh-add 1
adds the
adds the
.Pa $HOME/.ssh/identity
file.
If the identity has a passphrase,
If the identity has a passphrase,
.Xr ssh-add 1
asks for the passphrase (using a small X11 application if running
under X11, or from the terminal if running without X).
@ -152,7 +152,7 @@ external libraries.
.It
has been updated to support ssh protocol 1.5.
.It
contains added support for
contains added support for
.Xr kerberos 8
authentication and ticket passing.
.It

View File

@ -9,7 +9,7 @@
.\"
.\" Created: Sat Apr 22 23:55:14 1995 ylo
.\"
.\" $Id: ssh-keygen.1,v 1.12 2000/03/23 21:10:10 aaron Exp $
.\" $Id: ssh-keygen.1,v 1.18 2000/05/08 17:26:04 hugh Exp $
.\"
.Dd September 25, 1999
.Dt SSH-KEYGEN 1
@ -19,7 +19,7 @@
.Nd authentication key generation
.Sh SYNOPSIS
.Nm ssh-keygen
.Op Fl q
.Op Fl dq
.Op Fl b Ar bits
.Op Fl N Ar new_passphrase
.Op Fl C Ar comment
@ -30,6 +30,15 @@
.Op Fl N Ar new_passphrase
.Op Fl f Ar keyfile
.Nm ssh-keygen
.Fl x
.Op Fl f Ar keyfile
.Nm ssh-keygen
.Fl X
.Op Fl f Ar keyfile
.Nm ssh-keygen
.Fl y
.Op Fl f Ar keyfile
.Nm ssh-keygen
.Fl c
.Op Fl P Ar passphrase
.Op Fl C Ar comment
@ -37,15 +46,27 @@
.Nm ssh-keygen
.Fl l
.Op Fl f Ar keyfile
.Sh DESCRIPTION
.Nm ssh-keygen
.Fl R
.Sh DESCRIPTION
.Nm
generates and manages authentication keys for
generates and manages authentication keys for
.Xr ssh 1 .
.Nm
defaults to generating an RSA key for use by protocols 1.3 and 1.5;
specifying the
.Fl d
flag will create a DSA key instead for use by protocol 2.0.
.Pp
Normally each user wishing to use SSH
with RSA authentication runs this once to create the authentication
with RSA or DSA authentication runs this once to create the authentication
key in
.Pa $HOME/.ssh/identity .
Additionally, the system administrator may use this to generate host keys.
.Pa $HOME/.ssh/identity
or
.Pa $HOME/.ssh/id_dsa .
Additionally, the system administrator may use this to generate host keys,
as seen in
.Pa /etc/rc .
.Pp
Normally this program generates the key and asks for a file in which
to store the private key.
@ -69,7 +90,7 @@ If the passphrase is
lost or forgotten, you will have to generate a new key and copy the
corresponding public key to other machines.
.Pp
There is also a comment field in the key file that is only for
For RSA, there is also a comment field in the key file that is only for
convenience to the user to help identify the key.
The comment can tell what the key is for, or whatever is useful.
The comment is initialized to
@ -78,6 +99,9 @@ when the key is created, but can be changed using the
.Fl c
option.
.Pp
After a key is generated, instructions below detail where the keys
should be placed to be activated.
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl b Ar bits
@ -112,6 +136,19 @@ Provides the new comment.
Provides the new passphrase.
.It Fl P Ar passphrase
Provides the (old) passphrase.
.It Fl R
If RSA support is functional, immediately exits with code 0. If RSA
support is not functional, exits with code 1. This flag will be
removed once the RSA patent expires.
.It Fl x
This option will read a private
OpenSSH DSA format file and print a SSH2-compatible public key to stdout.
.It Fl X
This option will read a
SSH2-compatible public key file and print an OpenSSH DSA compatible public key to stdout.
.It Fl y
This option will read a private
OpenSSH DSA format file and print an OpenSSH DSA public key to stdout.
.El
.Sh FILES
.Bl -tag -width Ds
@ -124,6 +161,8 @@ used to encrypt the private part of this file using 3DES.
This file is not automatically accessed by
.Nm
but it is offered as the default file for the private key.
.Xr sshd 8
will read this file when a login attempt is made.
.It Pa $HOME/.ssh/identity.pub
Contains the public key for authentication.
The contents of this file should be added to
@ -131,6 +170,24 @@ The contents of this file should be added to
on all machines
where you wish to log in using RSA authentication.
There is no need to keep the contents of this file secret.
.It Pa $HOME/.ssh/id_dsa
Contains the DSA authentication identity of the user.
This file should not be readable by anyone but the user.
It is possible to
specify a passphrase when generating the key; that passphrase will be
used to encrypt the private part of this file using 3DES.
This file is not automatically accessed by
.Nm
but it is offered as the default file for the private key.
.Xr sshd 8
will read this file when a login attempt is made.
.It Pa $HOME/.ssh/id_dsa.pub
Contains the public key for authentication.
The contents of this file should be added to
.Pa $HOME/.ssh/authorized_keys2
on all machines
where you wish to log in using DSA authentication.
There is no need to keep the contents of this file secret.
.Sh AUTHOR
Tatu Ylonen <ylo@cs.hut.fi>
.Pp
@ -150,7 +207,7 @@ external libraries.
.It
has been updated to support ssh protocol 1.5.
.It
contains added support for
contains added support for
.Xr kerberos 8
authentication and ticket passing.
.It

View File

@ -7,20 +7,23 @@
*/
#include "includes.h"
RCSID("$Id: ssh-keygen.c,v 1.17 2000/03/16 20:56:14 markus Exp $");
RCSID("$Id: ssh-keygen.c,v 1.25 2000/05/08 18:23:07 markus Exp $");
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include "rsa.h"
#include "ssh.h"
#include "xmalloc.h"
#include "fingerprint.h"
#include "key.h"
#include "rsa.h"
#include "dsa.h"
#include "authfile.h"
#include "uuencode.h"
/* Generated private key. */
RSA *private_key;
/* Generated public key. */
RSA *public_key;
/* Number of bits in the RSA key. This value can be changed on the command line. */
/* Number of bits in the RSA/DSA key. This value can be changed on the command line. */
int bits = 1024;
/*
@ -53,15 +56,24 @@ char *identity_new_passphrase = NULL;
/* This is set to the new comment if given on the command line. */
char *identity_comment = NULL;
/* Dump public key file in format used by real and the original SSH 2 */
int convert_to_ssh2 = 0;
int convert_from_ssh2 = 0;
int print_public = 0;
int dsa_mode = 0;
/* argv0 */
extern char *__progname;
char hostname[MAXHOSTNAMELEN];
void
ask_filename(struct passwd *pw, const char *prompt)
{
char buf[1024];
snprintf(identity_file, sizeof(identity_file), "%s/%s",
pw->pw_dir, SSH_CLIENT_IDENTITY);
pw->pw_dir,
dsa_mode ? SSH_CLIENT_ID_DSA: SSH_CLIENT_IDENTITY);
printf("%s (%s): ", prompt, identity_file);
fflush(stdout);
if (fgets(buf, sizeof(buf), stdin) == NULL)
@ -73,12 +85,148 @@ ask_filename(struct passwd *pw, const char *prompt)
have_identity = 1;
}
int
try_load_key(char *filename, Key *k)
{
int success = 1;
if (!load_private_key(filename, "", k, NULL)) {
char *pass = read_passphrase("Enter passphrase: ", 1);
if (!load_private_key(filename, pass, k, NULL)) {
success = 0;
}
memset(pass, 0, strlen(pass));
xfree(pass);
}
return success;
}
#define SSH_COM_MAGIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
#define SSH_COM_MAGIC_END "---- END SSH2 PUBLIC KEY ----"
void
do_convert_to_ssh2(struct passwd *pw)
{
Key *k;
int len;
unsigned char *blob;
struct stat st;
if (!have_identity)
ask_filename(pw, "Enter file in which the key is");
if (stat(identity_file, &st) < 0) {
perror(identity_file);
exit(1);
}
k = key_new(KEY_DSA);
if (!try_load_key(identity_file, k)) {
fprintf(stderr, "load failed\n");
exit(1);
}
dsa_make_key_blob(k, &blob, &len);
fprintf(stdout, SSH_COM_MAGIC_BEGIN "\n");
fprintf(stdout,
"Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n",
BN_num_bits(k->dsa->p),
pw->pw_name, hostname);
dump_base64(stdout, blob, len);
fprintf(stdout, SSH_COM_MAGIC_END "\n");
key_free(k);
xfree(blob);
exit(0);
}
void
do_convert_from_ssh2(struct passwd *pw)
{
Key *k;
int blen;
char line[1024], *p;
char blob[8096];
char encoded[8096];
struct stat st;
int escaped = 0;
FILE *fp;
if (!have_identity)
ask_filename(pw, "Enter file in which the key is");
if (stat(identity_file, &st) < 0) {
perror(identity_file);
exit(1);
}
fp = fopen(identity_file, "r");
if (fp == NULL) {
perror(identity_file);
exit(1);
}
encoded[0] = '\0';
while (fgets(line, sizeof(line), fp)) {
if (!(p = strchr(line, '\n'))) {
fprintf(stderr, "input line too long.\n");
exit(1);
}
if (p > line && p[-1] == '\\')
escaped++;
if (strncmp(line, "----", 4) == 0 ||
strstr(line, ": ") != NULL) {
fprintf(stderr, "ignore: %s", line);
continue;
}
if (escaped) {
escaped--;
fprintf(stderr, "escaped: %s", line);
continue;
}
*p = '\0';
strlcat(encoded, line, sizeof(encoded));
}
blen = uudecode(encoded, (unsigned char *)blob, sizeof(blob));
if (blen < 0) {
fprintf(stderr, "uudecode failed.\n");
exit(1);
}
k = dsa_key_from_blob(blob, blen);
if (!key_write(k, stdout))
fprintf(stderr, "key_write failed");
key_free(k);
fprintf(stdout, "\n");
fclose(fp);
exit(0);
}
void
do_print_public(struct passwd *pw)
{
Key *k;
int len;
unsigned char *blob;
struct stat st;
if (!have_identity)
ask_filename(pw, "Enter file in which the key is");
if (stat(identity_file, &st) < 0) {
perror(identity_file);
exit(1);
}
k = key_new(KEY_DSA);
if (!try_load_key(identity_file, k)) {
fprintf(stderr, "load failed\n");
exit(1);
}
dsa_make_key_blob(k, &blob, &len);
if (!key_write(k, stdout))
fprintf(stderr, "key_write failed");
key_free(k);
xfree(blob);
fprintf(stdout, "\n");
exit(0);
}
void
do_fingerprint(struct passwd *pw)
{
FILE *f;
BIGNUM *e, *n;
RSA *public_key;
Key *public;
char *comment = NULL, *cp, *ep, line[16*1024];
int i, skip = 0, num = 1, invalid = 1;
unsigned int ignore;
@ -90,17 +238,16 @@ do_fingerprint(struct passwd *pw)
perror(identity_file);
exit(1);
}
public_key = RSA_new();
if (load_public_key(identity_file, public_key, &comment)) {
printf("%d %s %s\n", BN_num_bits(public_key->n),
fingerprint(public_key->e, public_key->n),
comment);
RSA_free(public_key);
public = key_new(KEY_RSA);
if (load_public_key(identity_file, public, &comment)) {
printf("%d %s %s\n", BN_num_bits(public->rsa->n),
key_fingerprint(public), comment);
key_free(public);
exit(0);
}
RSA_free(public_key);
key_free(public);
/* XXX */
f = fopen(identity_file, "r");
if (f != NULL) {
n = BN_new();
@ -168,7 +315,9 @@ do_change_passphrase(struct passwd *pw)
char *comment;
char *old_passphrase, *passphrase1, *passphrase2;
struct stat st;
RSA *private_key;
Key *private;
Key *public;
int type = dsa_mode ? KEY_DSA : KEY_RSA;
if (!have_identity)
ask_filename(pw, "Enter file in which the key is");
@ -176,22 +325,26 @@ do_change_passphrase(struct passwd *pw)
perror(identity_file);
exit(1);
}
public_key = RSA_new();
if (!load_public_key(identity_file, public_key, NULL)) {
printf("%s is not a valid key file.\n", identity_file);
exit(1);
if (type == KEY_RSA) {
/* XXX this works currently only for RSA */
public = key_new(type);
if (!load_public_key(identity_file, public, NULL)) {
printf("%s is not a valid key file.\n", identity_file);
exit(1);
}
/* Clear the public key since we are just about to load the whole file. */
key_free(public);
}
/* Clear the public key since we are just about to load the whole file. */
RSA_free(public_key);
/* Try to load the file with empty passphrase. */
private_key = RSA_new();
if (!load_private_key(identity_file, "", private_key, &comment)) {
private = key_new(type);
if (!load_private_key(identity_file, "", private, &comment)) {
if (identity_passphrase)
old_passphrase = xstrdup(identity_passphrase);
else
old_passphrase = read_passphrase("Enter old passphrase: ", 1);
if (!load_private_key(identity_file, old_passphrase, private_key, &comment)) {
if (!load_private_key(identity_file, old_passphrase, private, &comment)) {
memset(old_passphrase, 0, strlen(old_passphrase));
xfree(old_passphrase);
printf("Bad passphrase.\n");
@ -226,19 +379,19 @@ do_change_passphrase(struct passwd *pw)
}
/* Save the file using the new passphrase. */
if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
if (!save_private_key(identity_file, passphrase1, private, comment)) {
printf("Saving the key failed: %s: %s.\n",
identity_file, strerror(errno));
memset(passphrase1, 0, strlen(passphrase1));
xfree(passphrase1);
RSA_free(private_key);
key_free(private);
xfree(comment);
exit(1);
}
/* Destroy the passphrase and the copy of the key in memory. */
memset(passphrase1, 0, strlen(passphrase1));
xfree(passphrase1);
RSA_free(private_key); /* Destroys contents */
key_free(private); /* Destroys contents */
xfree(comment);
printf("Your identification has been saved with the new passphrase.\n");
@ -252,11 +405,11 @@ void
do_change_comment(struct passwd *pw)
{
char new_comment[1024], *comment;
RSA *private_key;
Key *private;
Key *public;
char *passphrase;
struct stat st;
FILE *f;
char *tmpbuf;
if (!have_identity)
ask_filename(pw, "Enter file in which the key is");
@ -268,14 +421,14 @@ do_change_comment(struct passwd *pw)
* Try to load the public key from the file the verify that it is
* readable and of the proper format.
*/
public_key = RSA_new();
if (!load_public_key(identity_file, public_key, NULL)) {
public = key_new(KEY_RSA);
if (!load_public_key(identity_file, public, NULL)) {
printf("%s is not a valid key file.\n", identity_file);
exit(1);
}
private_key = RSA_new();
if (load_private_key(identity_file, "", private_key, &comment))
private = key_new(KEY_RSA);
if (load_private_key(identity_file, "", private, &comment))
passphrase = xstrdup("");
else {
if (identity_passphrase)
@ -285,7 +438,7 @@ do_change_comment(struct passwd *pw)
else
passphrase = read_passphrase("Enter passphrase: ", 1);
/* Try to load using the passphrase. */
if (!load_private_key(identity_file, passphrase, private_key, &comment)) {
if (!load_private_key(identity_file, passphrase, private, &comment)) {
memset(passphrase, 0, strlen(passphrase));
xfree(passphrase);
printf("Bad passphrase.\n");
@ -301,7 +454,7 @@ do_change_comment(struct passwd *pw)
fflush(stdout);
if (!fgets(new_comment, sizeof(new_comment), stdin)) {
memset(passphrase, 0, strlen(passphrase));
RSA_free(private_key);
key_free(private);
exit(1);
}
if (strchr(new_comment, '\n'))
@ -309,18 +462,18 @@ do_change_comment(struct passwd *pw)
}
/* Save the file using the new passphrase. */
if (!save_private_key(identity_file, passphrase, private_key, new_comment)) {
if (!save_private_key(identity_file, passphrase, private, new_comment)) {
printf("Saving the key failed: %s: %s.\n",
identity_file, strerror(errno));
memset(passphrase, 0, strlen(passphrase));
xfree(passphrase);
RSA_free(private_key);
key_free(private);
xfree(comment);
exit(1);
}
memset(passphrase, 0, strlen(passphrase));
xfree(passphrase);
RSA_free(private_key);
key_free(private);
strlcat(identity_file, ".pub", sizeof(identity_file));
f = fopen(identity_file, "w");
@ -328,13 +481,10 @@ do_change_comment(struct passwd *pw)
printf("Could not save your public key in %s\n", identity_file);
exit(1);
}
fprintf(f, "%d ", BN_num_bits(public_key->n));
tmpbuf = BN_bn2dec(public_key->e);
fprintf(f, "%s ", tmpbuf);
free(tmpbuf);
tmpbuf = BN_bn2dec(public_key->n);
fprintf(f, "%s %s\n", tmpbuf, new_comment);
free(tmpbuf);
if (!key_write(public, f))
fprintf(stderr, "write key failed");
key_free(public);
fprintf(f, " %s\n", new_comment);
fclose(f);
xfree(comment);
@ -346,8 +496,7 @@ do_change_comment(struct passwd *pw)
void
usage(void)
{
printf("ssh-keygen version %s\n", SSH_VERSION);
printf("Usage: %s [-b bits] [-p] [-c] [-l] [-f file] [-P pass] [-N new-pass] [-C comment]\n", __progname);
printf("Usage: %s [-lpqxXydc] [-b bits] [-f file] [-C comment] [-N new-pass] [-P pass]\n", __progname);
exit(1);
}
@ -359,29 +508,28 @@ main(int ac, char **av)
{
char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
struct passwd *pw;
char *tmpbuf;
int opt;
struct stat st;
FILE *f;
char hostname[MAXHOSTNAMELEN];
Key *private;
Key *public;
extern int optind;
extern char *optarg;
/* check if RSA support exists */
if (rsa_alive() == 0) {
fprintf(stderr,
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
__progname);
exit(1);
}
OpenSSL_add_all_algorithms();
/* we need this for the home * directory. */
pw = getpwuid(getuid());
if (!pw) {
printf("You don't exist, go away!\n");
exit(1);
}
if (gethostname(hostname, sizeof(hostname)) < 0) {
perror("gethostname");
exit(1);
}
while ((opt = getopt(ac, av, "qpclb:f:P:N:C:")) != EOF) {
while ((opt = getopt(ac, av, "dqpclRxXyb:f:P:N:C:")) != EOF) {
switch (opt) {
case 'b':
bits = atoi(optarg);
@ -424,6 +572,29 @@ main(int ac, char **av)
quiet = 1;
break;
case 'R':
if (rsa_alive() == 0)
exit(1);
else
exit(0);
break;
case 'x':
convert_to_ssh2 = 1;
break;
case 'X':
convert_from_ssh2 = 1;
break;
case 'y':
print_public = 1;
break;
case 'd':
dsa_mode = 1;
break;
case '?':
default:
usage();
@ -437,22 +608,44 @@ main(int ac, char **av)
printf("Can only have one of -p and -c.\n");
usage();
}
/* check if RSA support is needed and exists */
if (dsa_mode == 0 && rsa_alive() == 0) {
fprintf(stderr,
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
__progname);
exit(1);
}
if (print_fingerprint)
do_fingerprint(pw);
if (change_passphrase)
do_change_passphrase(pw);
if (change_comment)
do_change_comment(pw);
if (convert_to_ssh2)
do_convert_to_ssh2(pw);
if (convert_from_ssh2)
do_convert_from_ssh2(pw);
if (print_public)
do_print_public(pw);
arc4random_stir();
if (quiet)
rsa_set_verbose(0);
/* Generate the rsa key pair. */
private_key = RSA_new();
public_key = RSA_new();
rsa_generate_key(private_key, public_key, bits);
if (dsa_mode != 0) {
if (!quiet)
printf("Generating DSA parameter and key.\n");
public = private = dsa_generate_key(bits);
if (private == NULL) {
fprintf(stderr, "dsa_generate_keys failed");
exit(1);
}
} else {
if (quiet)
rsa_set_verbose(0);
/* Generate the rsa key pair. */
public = key_new(KEY_RSA);
private = key_new(KEY_RSA);
rsa_generate_key(private->rsa, public->rsa, bits);
}
if (!have_identity)
ask_filename(pw, "Enter file in which to save the key");
@ -504,18 +697,14 @@ main(int ac, char **av)
if (identity_comment) {
strlcpy(comment, identity_comment, sizeof(comment));
} else {
/* Create default commend field for the passphrase. */
if (gethostname(hostname, sizeof(hostname)) < 0) {
perror("gethostname");
exit(1);
}
/* Create default commend field for the passphrase. */
snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
}
/* Save the key with the given passphrase and comment. */
if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
if (!save_private_key(identity_file, passphrase1, private, comment)) {
printf("Saving the key failed: %s: %s.\n",
identity_file, strerror(errno));
identity_file, strerror(errno));
memset(passphrase1, 0, strlen(passphrase1));
xfree(passphrase1);
exit(1);
@ -525,7 +714,9 @@ main(int ac, char **av)
xfree(passphrase1);
/* Clear the private key and the random number generator. */
RSA_free(private_key);
if (private != public) {
key_free(private);
}
arc4random_stir();
if (!quiet)
@ -537,21 +728,18 @@ main(int ac, char **av)
printf("Could not save your public key in %s\n", identity_file);
exit(1);
}
fprintf(f, "%d ", BN_num_bits(public_key->n));
tmpbuf = BN_bn2dec(public_key->e);
fprintf(f, "%s ", tmpbuf);
free(tmpbuf);
tmpbuf = BN_bn2dec(public_key->n);
fprintf(f, "%s %s\n", tmpbuf, comment);
free(tmpbuf);
if (!key_write(public, f))
fprintf(stderr, "write key failed");
fprintf(f, " %s\n", comment);
fclose(f);
if (!quiet) {
printf("Your public key has been saved in %s.\n", identity_file);
printf("Your public key has been saved in %s.\n",
identity_file);
printf("The key fingerprint is:\n");
printf("%d %s %s\n", BN_num_bits(public_key->n),
fingerprint(public_key->e, public_key->n),
comment);
printf("%s %s\n", key_fingerprint(public), comment);
}
key_free(public);
exit(0);
}

View File

@ -15,7 +15,8 @@ MAN= ssh.1
LINKS= ${BINDIR}/ssh ${BINDIR}/slogin
MLINKS= ssh.1 slogin.1
SRCS= ssh.c sshconnect.c log-client.c readconf.c clientloop.c
SRCS= ssh.c log-client.c readconf.c clientloop.c \
sshconnect.c sshconnect1.c sshconnect2.c
.include <bsd.own.mk> # for AFS

106
crypto/openssh/ssh2.h Normal file
View File

@ -0,0 +1,106 @@
/*
* draft-ietf-secsh-architecture-04.txt
*
* Transport layer protocol:
*
* 1-19 Transport layer generic (e.g. disconnect, ignore, debug,
* etc)
* 20-29 Algorithm negotiation
* 30-49 Key exchange method specific (numbers can be reused for
* different authentication methods)
*
* User authentication protocol:
*
* 50-59 User authentication generic
* 60-79 User authentication method specific (numbers can be reused
* for different authentication methods)
*
* Connection protocol:
*
* 80-89 Connection protocol generic
* 90-127 Channel related messages
*
* Reserved for client protocols:
*
* 128-191 Reserved
*
* Local extensions:
*
* 192-255 Local extensions
*/
/* transport layer: generic */
#define SSH2_MSG_DISCONNECT 1
#define SSH2_MSG_IGNORE 2
#define SSH2_MSG_UNIMPLEMENTED 3
#define SSH2_MSG_DEBUG 4
#define SSH2_MSG_SERVICE_REQUEST 5
#define SSH2_MSG_SERVICE_ACCEPT 6
/* transport layer: alg negotiation */
#define SSH2_MSG_KEXINIT 20
#define SSH2_MSG_NEWKEYS 21
/* transport layer: kex specific messages, can be reused */
#define SSH2_MSG_KEXDH_INIT 30
#define SSH2_MSG_KEXDH_REPLY 31
/* user authentication: generic */
#define SSH2_MSG_USERAUTH_REQUEST 50
#define SSH2_MSG_USERAUTH_FAILURE 51
#define SSH2_MSG_USERAUTH_SUCCESS 52
#define SSH2_MSG_USERAUTH_BANNER 53
/* user authentication: method specific, can be reused */
#define SSH2_MSG_USERAUTH_PK_OK 60
#define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60
#define SSH2_MSG_USERAUTH_INFO_REQUEST 60
#define SSH2_MSG_USERAUTH_INFO_RESPONSE 61
/* connection protocol: generic */
#define SSH2_MSG_GLOBAL_REQUEST 80
#define SSH2_MSG_REQUEST_SUCCESS 81
#define SSH2_MSG_REQUEST_FAILURE 82
/* channel related messages */
#define SSH2_MSG_CHANNEL_OPEN 90
#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91
#define SSH2_MSG_CHANNEL_OPEN_FAILURE 92
#define SSH2_MSG_CHANNEL_WINDOW_ADJUST 93
#define SSH2_MSG_CHANNEL_DATA 94
#define SSH2_MSG_CHANNEL_EXTENDED_DATA 95
#define SSH2_MSG_CHANNEL_EOF 96
#define SSH2_MSG_CHANNEL_CLOSE 97
#define SSH2_MSG_CHANNEL_REQUEST 98
#define SSH2_MSG_CHANNEL_SUCCESS 99
#define SSH2_MSG_CHANNEL_FAILURE 100
/* disconnect reason code */
#define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1
#define SSH2_DISCONNECT_PROTOCOL_ERROR 2
#define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED 3
#define SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED 4
#define SSH2_DISCONNECT_MAC_ERROR 5
#define SSH2_DISCONNECT_COMPRESSION_ERROR 6
#define SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE 7
#define SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8
#define SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9
#define SSH2_DISCONNECT_CONNECTION_LOST 10
#define SSH2_DISCONNECT_BY_APPLICATION 11
/* misc */
#define SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED 1
#define SSH2_OPEN_CONNECT_FAILED 2
#define SSH2_OPEN_UNKNOWN_CHANNEL_TYPE 3
#define SSH2_OPEN_RESOURCE_SHORTAGE 4
#define SSH2_EXTENDED_DATA_STDERR 1

View File

@ -0,0 +1,16 @@
#ifndef SSHCONNECT_H
#define SSHCONNECT_H
void
check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
const char *user_hostfile, const char *system_hostfile);
void ssh_kex(char *host, struct sockaddr *hostaddr);
void
ssh_userauth(const char* local_user, const char* server_user, char *host,
int host_key_valid, RSA *own_host_key);
void ssh_kex2(char *host, struct sockaddr *hostaddr);
void ssh_userauth2(const char *server_user, char *host);
#endif

1024
crypto/openssh/sshconnect1.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,474 @@
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Markus Friedl.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: sshconnect2.c,v 1.10 2000/05/08 17:42:25 markus Exp $");
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/md5.h>
#include <openssl/dh.h>
#include <openssl/hmac.h>
#include "ssh.h"
#include "xmalloc.h"
#include "rsa.h"
#include "buffer.h"
#include "packet.h"
#include "cipher.h"
#include "uidswap.h"
#include "compat.h"
#include "readconf.h"
#include "bufaux.h"
#include "ssh2.h"
#include "kex.h"
#include "myproposal.h"
#include "key.h"
#include "dsa.h"
#include "sshconnect.h"
#include "authfile.h"
/* import */
extern char *client_version_string;
extern char *server_version_string;
extern Options options;
/*
* SSH2 key exchange
*/
unsigned char *session_id2 = NULL;
int session_id2_len = 0;
void
ssh_kex2(char *host, struct sockaddr *hostaddr)
{
Kex *kex;
char *cprop[PROPOSAL_MAX];
char *sprop[PROPOSAL_MAX];
Buffer *client_kexinit;
Buffer *server_kexinit;
int payload_len, dlen;
unsigned int klen, kout;
char *ptr;
char *signature = NULL;
unsigned int slen;
char *server_host_key_blob = NULL;
Key *server_host_key;
unsigned int sbloblen;
DH *dh;
BIGNUM *dh_server_pub = 0;
BIGNUM *shared_secret = 0;
int i;
unsigned char *kbuf;
unsigned char *hash;
/* KEXINIT */
debug("Sending KEX init.");
if (options.ciphers != NULL) {
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
} else if (options.cipher == SSH_CIPHER_3DES) {
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
myproposal[PROPOSAL_ENC_ALGS_STOC] =
cipher_name(SSH_CIPHER_3DES_CBC);
} else if (options.cipher == SSH_CIPHER_BLOWFISH) {
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
myproposal[PROPOSAL_ENC_ALGS_STOC] =
cipher_name(SSH_CIPHER_BLOWFISH_CBC);
}
if (options.compression) {
myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib";
myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib";
} else {
myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none";
myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
}
for (i = 0; i < PROPOSAL_MAX; i++)
cprop[i] = xstrdup(myproposal[i]);
client_kexinit = kex_init(cprop);
packet_start(SSH2_MSG_KEXINIT);
packet_put_raw(buffer_ptr(client_kexinit), buffer_len(client_kexinit));
packet_send();
packet_write_wait();
debug("done");
packet_read_expect(&payload_len, SSH2_MSG_KEXINIT);
/* save payload for session_id */
server_kexinit = xmalloc(sizeof(*server_kexinit));
buffer_init(server_kexinit);
ptr = packet_get_raw(&payload_len);
buffer_append(server_kexinit, ptr, payload_len);
/* skip cookie */
for (i = 0; i < 16; i++)
(void) packet_get_char();
/* kex init proposal strings */
for (i = 0; i < PROPOSAL_MAX; i++) {
sprop[i] = packet_get_string(NULL);
debug("got kexinit string: %s", sprop[i]);
}
i = (int) packet_get_char();
debug("first kex follow == %d", i);
i = packet_get_int();
debug("reserved == %d", i);
packet_done();
debug("done read kexinit");
kex = kex_choose_conf(cprop, sprop, 0);
/* KEXDH */
debug("Sending SSH2_MSG_KEXDH_INIT.");
/* generate and send 'e', client DH public key */
dh = dh_new_group1();
packet_start(SSH2_MSG_KEXDH_INIT);
packet_put_bignum2(dh->pub_key);
packet_send();
packet_write_wait();
#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");
DHparams_print_fp(stderr, dh);
#endif
debug("Wait SSH2_MSG_KEXDH_REPLY.");
packet_read_expect(&payload_len, SSH2_MSG_KEXDH_REPLY);
debug("Got SSH2_MSG_KEXDH_REPLY.");
/* key, cert */
server_host_key_blob = packet_get_string(&sbloblen);
server_host_key = dsa_key_from_blob(server_host_key_blob, sbloblen);
if (server_host_key == NULL)
fatal("cannot decode server_host_key_blob");
check_host_key(host, hostaddr, server_host_key,
options.user_hostfile2, options.system_hostfile2);
/* DH paramter f, server public DH key */
dh_server_pub = BN_new();
if (dh_server_pub == NULL)
fatal("dh_server_pub == NULL");
packet_get_bignum2(dh_server_pub, &dlen);
#ifdef DEBUG_KEXDH
fprintf(stderr, "\ndh_server_pub= ");
bignum_print(dh_server_pub);
fprintf(stderr, "\n");
debug("bits %d", BN_num_bits(dh_server_pub));
#endif
/* signed H */
signature = packet_get_string(&slen);
packet_done();
if (!dh_pub_is_valid(dh, dh_server_pub))
packet_disconnect("bad server public DH value");
klen = DH_size(dh);
kbuf = xmalloc(klen);
kout = DH_compute_key(kbuf, dh_server_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);
/* calc and verify H */
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),
server_host_key_blob, sbloblen,
dh->pub_key,
dh_server_pub,
shared_secret
);
xfree(server_host_key_blob);
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
if (dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1)
fatal("dsa_verify failed for server_host_key");
key_free(server_host_key);
kex_derive_keys(kex, hash, shared_secret);
packet_set_kex(kex);
/* have keys, free DH */
DH_free(dh);
/* save session id */
session_id2_len = 20;
session_id2 = xmalloc(session_id2_len);
memcpy(session_id2, hash, session_id2_len);
debug("Wait SSH2_MSG_NEWKEYS.");
packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS);
packet_done();
debug("GOT SSH2_MSG_NEWKEYS.");
debug("send SSH2_MSG_NEWKEYS.");
packet_start(SSH2_MSG_NEWKEYS);
packet_send();
packet_write_wait();
debug("done: send SSH2_MSG_NEWKEYS.");
#ifdef DEBUG_KEXDH
/* send 1st encrypted/maced/compressed message */
packet_start(SSH2_MSG_IGNORE);
packet_put_cstring("markus");
packet_send();
packet_write_wait();
#endif
debug("done: KEX2.");
}
/*
* Authenticate user
*/
int
ssh2_try_passwd(const char *server_user, const char *host, const char *service)
{
static int attempt = 0;
char prompt[80];
char *password;
if (attempt++ > options.number_of_password_prompts)
return 0;
snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ",
server_user, host);
password = read_passphrase(prompt, 0);
packet_start(SSH2_MSG_USERAUTH_REQUEST);
packet_put_cstring(server_user);
packet_put_cstring(service);
packet_put_cstring("password");
packet_put_char(0);
packet_put_cstring(password);
memset(password, 0, strlen(password));
xfree(password);
packet_send();
packet_write_wait();
return 1;
}
int
ssh2_try_pubkey(char *filename,
const char *server_user, const char *host, const char *service)
{
Buffer b;
Key *k;
unsigned char *blob, *signature;
int bloblen, slen;
struct stat st;
if (stat(filename, &st) != 0) {
debug("key does not exist: %s", filename);
return 0;
}
debug("try pubkey: %s", filename);
k = key_new(KEY_DSA);
if (!load_private_key(filename, "", k, NULL)) {
int success = 0;
char *passphrase;
char prompt[300];
snprintf(prompt, sizeof prompt,
"Enter passphrase for DSA key '%.100s': ",
filename);
passphrase = read_passphrase(prompt, 0);
success = load_private_key(filename, passphrase, k, NULL);
memset(passphrase, 0, strlen(passphrase));
xfree(passphrase);
if (!success)
return 0;
}
dsa_make_key_blob(k, &blob, &bloblen);
/* data to be signed */
buffer_init(&b);
buffer_append(&b, session_id2, session_id2_len);
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
buffer_put_cstring(&b, server_user);
buffer_put_cstring(&b,
datafellows & SSH_BUG_PUBKEYAUTH ?
"ssh-userauth" :
service);
buffer_put_cstring(&b, "publickey");
buffer_put_char(&b, 1);
buffer_put_cstring(&b, KEX_DSS);
buffer_put_string(&b, blob, bloblen);
/* generate signature */
dsa_sign(k, &signature, &slen, buffer_ptr(&b), buffer_len(&b));
key_free(k);
#ifdef DEBUG_DSS
buffer_dump(&b);
#endif
if (datafellows & SSH_BUG_PUBKEYAUTH) {
/* e.g. ssh-2.0.13: data-to-be-signed != data-on-the-wire */
buffer_clear(&b);
buffer_append(&b, session_id2, session_id2_len);
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
buffer_put_cstring(&b, server_user);
buffer_put_cstring(&b, service);
buffer_put_cstring(&b, "publickey");
buffer_put_char(&b, 1);
buffer_put_cstring(&b, KEX_DSS);
buffer_put_string(&b, blob, bloblen);
}
xfree(blob);
/* append signature */
buffer_put_string(&b, signature, slen);
xfree(signature);
/* skip session id and packet type */
if (buffer_len(&b) < session_id2_len + 1)
fatal("ssh2_try_pubkey: internal error");
buffer_consume(&b, session_id2_len + 1);
/* put remaining data from buffer into packet */
packet_start(SSH2_MSG_USERAUTH_REQUEST);
packet_put_raw(buffer_ptr(&b), buffer_len(&b));
buffer_free(&b);
/* send */
packet_send();
packet_write_wait();
return 1;
}
void
ssh_userauth2(const char *server_user, char *host)
{
int type;
int plen;
int sent;
unsigned int dlen;
int partial;
int i = 0;
char *auths;
char *service = "ssh-connection"; /* service name */
debug("send SSH2_MSG_SERVICE_REQUEST");
packet_start(SSH2_MSG_SERVICE_REQUEST);
packet_put_cstring("ssh-userauth");
packet_send();
packet_write_wait();
type = packet_read(&plen);
if (type != SSH2_MSG_SERVICE_ACCEPT) {
fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);
}
if (packet_remaining() > 0) {
char *reply = packet_get_string(&plen);
debug("service_accept: %s", reply);
xfree(reply);
} else {
/* payload empty for ssh-2.0.13 ?? */
debug("buggy server: service_accept w/o service");
}
packet_done();
debug("got SSH2_MSG_SERVICE_ACCEPT");
/* INITIAL request for auth */
packet_start(SSH2_MSG_USERAUTH_REQUEST);
packet_put_cstring(server_user);
packet_put_cstring(service);
packet_put_cstring("none");
packet_send();
packet_write_wait();
for (;;) {
sent = 0;
type = packet_read(&plen);
if (type == SSH2_MSG_USERAUTH_SUCCESS)
break;
if (type != SSH2_MSG_USERAUTH_FAILURE)
fatal("access denied: %d", type);
/* SSH2_MSG_USERAUTH_FAILURE means: try again */
auths = packet_get_string(&dlen);
debug("authentications that can continue: %s", auths);
partial = packet_get_char();
packet_done();
if (partial)
debug("partial success");
if (options.dsa_authentication &&
strstr(auths, "publickey") != NULL) {
while (i < options.num_identity_files2) {
sent = ssh2_try_pubkey(
options.identity_files2[i++],
server_user, host, service);
if (sent)
break;
}
}
if (!sent) {
if (options.password_authentication &&
!options.batch_mode &&
strstr(auths, "password") != NULL) {
sent = ssh2_try_passwd(server_user, host, service);
}
}
if (!sent)
fatal("Permission denied (%s).", auths);
xfree(auths);
}
packet_done();
debug("ssh-userauth2 successfull");
}

View File

@ -7,7 +7,8 @@ BINDIR= /usr/sbin
MAN= sshd.8
SRCS= sshd.c auth-rhosts.c auth-passwd.c auth-rsa.c auth-rh-rsa.c \
pty.c log-server.c login.c servconf.c serverloop.c
pty.c log-server.c login.c servconf.c serverloop.c \
auth.c auth1.c auth2.c session.c
.include <bsd.own.mk> # for KERBEROS and AFS

View File

@ -10,7 +10,7 @@
*/
#include "includes.h"
RCSID("$Id: ttymodes.c,v 1.5 1999/11/24 19:53:54 markus Exp $");
RCSID("$Id: ttymodes.c,v 1.6 2000/04/14 10:30:34 markus Exp $");
#include "packet.h"
#include "ssh.h"
@ -23,7 +23,7 @@ RCSID("$Id: ttymodes.c,v 1.5 1999/11/24 19:53:54 markus Exp $");
* Converts POSIX speed_t to a baud rate. The values of the
* constants for speed_t are not themselves portable.
*/
static int
static int
speed_to_baud(speed_t speed)
{
switch (speed) {
@ -112,7 +112,7 @@ speed_to_baud(speed_t speed)
/*
* Converts a numeric baud rate to a POSIX speed_t.
*/
static speed_t
static speed_t
baud_to_speed(int baud)
{
switch (baud) {
@ -203,7 +203,7 @@ baud_to_speed(int baud)
* in a portable manner, and appends the modes to a packet
* being constructed.
*/
void
void
tty_make_modes(int fd)
{
struct termios tio;
@ -247,7 +247,7 @@ tty_make_modes(int fd)
* Decodes terminal modes for the terminal referenced by fd in a portable
* manner from a packet being read.
*/
void
void
tty_parse_modes(int fd, int *n_bytes_ptr)
{
struct termios tio;

View File

@ -1,18 +1,18 @@
/*
*
*
* ttymodes.h
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* SGTTY stuff contributed by Janne Snabb <snabb@niksula.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Tue Mar 21 15:42:09 1995 ylo
*
*
*/
/* RCSID("$Id: ttymodes.h,v 1.6 1999/11/24 19:53:54 markus Exp $"); */
/* RCSID("$Id: ttymodes.h,v 1.7 2000/04/14 10:30:34 markus Exp $"); */
/* The tty mode description is a stream of bytes. The stream consists of
* opcode-arguments pairs. It is terminated by opcode TTY_OP_END (0).

View File

@ -7,7 +7,7 @@
*/
#include "includes.h"
RCSID("$Id: uidswap.c,v 1.5 1999/11/24 19:53:54 markus Exp $");
RCSID("$Id: uidswap.c,v 1.6 2000/04/14 10:30:34 markus Exp $");
#include "ssh.h"
#include "uidswap.h"
@ -34,7 +34,7 @@ static uid_t saved_euid = 0;
* Temporarily changes to the given uid. If the effective user
* id is not root, this does nothing. This call cannot be nested.
*/
void
void
temporarily_use_uid(uid_t uid)
{
#ifdef SAVED_IDS_WORK_WITH_SETEUID
@ -58,7 +58,7 @@ temporarily_use_uid(uid_t uid)
/*
* Restores to the original uid.
*/
void
void
restore_uid()
{
#ifdef SAVED_IDS_WORK_WITH_SETEUID
@ -79,7 +79,7 @@ restore_uid()
* Permanently sets all uids to the given uid. This cannot be
* called while temporarily_use_uid is effective.
*/
void
void
permanently_set_uid(uid_t uid)
{
if (setuid(uid) < 0)

View File

@ -1,15 +1,15 @@
/*
*
*
* uidswap.h
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Sat Sep 9 01:43:15 1995 ylo
* Last modified: Sat Sep 9 02:34:04 1995 ylo
*
*
*/
#ifndef UIDSWAP_H

50
crypto/openssh/uuencode.c Normal file
View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*/
#include "includes.h"
#include "xmalloc.h"
#include <resolv.h>
int
uuencode(unsigned char *src, unsigned int srclength,
char *target, size_t targsize)
{
return __b64_ntop(src, srclength, target, targsize);
}
int
uudecode(const char *src, unsigned char *target, size_t targsize)
{
int len;
char *encoded, *p;
/* copy the 'readonly' source */
encoded = xstrdup(src);
/* skip whitespace and data */
for (p = encoded; *p == ' ' || *p == '\t'; p++)
;
for (; *p != '\0' && *p != ' ' && *p != '\t'; p++)
;
/* and remote trailing whitespace because __b64_pton needs this */
*p = '\0';
len = __b64_pton(encoded, target, targsize);
xfree(encoded);
return len;
}
void
dump_base64(FILE *fp, unsigned char *data, int len)
{
unsigned char *buf = xmalloc(2*len);
int i, n;
n = uuencode(data, len, buf, 2*len);
for (i = 0; i < n; i++) {
fprintf(fp, "%c", buf[i]);
if (i % 70 == 69)
fprintf(fp, "\n");
}
if (i % 70 != 69)
fprintf(fp, "\n");
xfree(buf);
}

View File

@ -0,0 +1,6 @@
#ifndef UUENCODE_H
#define UUENCODE_H
int uuencode(unsigned char *src, unsigned int srclength, char *target, size_t targsize);
int uudecode(const char *src, unsigned char *target, size_t targsize);
void dump_base64(FILE *fp, unsigned char *data, int len);
#endif

View File

@ -1 +1 @@
#define SSH_VERSION "OpenSSH-1.2.3"
#define SSH_VERSION "OpenSSH-2.1"

View File

@ -8,7 +8,7 @@
*/
#include "includes.h"
RCSID("$Id: xmalloc.c,v 1.5 1999/11/24 00:26:04 deraadt Exp $");
RCSID("$Id: xmalloc.c,v 1.6 2000/04/14 10:30:34 markus Exp $");
#include "ssh.h"
@ -34,7 +34,7 @@ xrealloc(void *ptr, size_t new_size)
return new_ptr;
}
void
void
xfree(void *ptr)
{
if (ptr == NULL)

View File

@ -1,20 +1,20 @@
/*
*
*
* xmalloc.h
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Mon Mar 20 22:09:17 1995 ylo
*
*
* Versions of malloc and friends that check their results, and never return
* failure (they call fatal if they encounter an error).
*
*
*/
/* RCSID("$Id: xmalloc.h,v 1.2 1999/11/24 00:26:04 deraadt Exp $"); */
/* RCSID("$Id: xmalloc.h,v 1.3 2000/04/14 10:30:34 markus Exp $"); */
#ifndef XMALLOC_H
#define XMALLOC_H