Initial import of OpenSSH v2.1.

This commit is contained in:
Kris Kennaway 2000-05-15 04:37:24 +00:00
parent a8f6863aa6
commit a04a10f891
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor-crypto/openssh/dist/; revision=60573
svn path=/vendor-crypto/openssh/2.1/; revision=60575; tag=vendor/openssh/2.1
102 changed files with 11284 additions and 5086 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

@ -19,7 +19,7 @@ extern ServerOptions options;
* return 1 on success, 0 on failure, -1 if krb4 is not available
*/
int
int
auth_krb4_password(struct passwd * pw, const char *password)
{
AUTH_DAT adata;
@ -135,7 +135,7 @@ krb4_cleanup_proc(void *ignore)
}
}
int
int
krb4_init(uid_t uid)
{
static int cleanup_registered = 0;
@ -179,7 +179,7 @@ krb4_init(uid_t uid)
return 0;
}
int
int
auth_krb4(const char *server_user, KTEXT auth, char **client)
{
AUTH_DAT adat = {0};
@ -252,7 +252,7 @@ auth_krb4(const char *server_user, KTEXT auth, char **client)
#endif /* KRB4 */
#ifdef AFS
int
int
auth_kerberos_tgt(struct passwd *pw, const char *string)
{
CREDENTIALS creds;
@ -307,7 +307,7 @@ auth_kerberos_tgt(struct passwd *pw, const char *string)
return 0;
}
int
int
auth_afs_token(struct passwd *pw, const char *token_string)
{
CREDENTIALS creds;

View File

@ -8,7 +8,7 @@
*/
#include "includes.h"
RCSID("$Id: auth-passwd.c,v 1.14 1999/12/29 12:47:46 markus Exp $");
RCSID("$Id: auth-passwd.c,v 1.15 2000/04/14 10:30:29 markus Exp $");
#include "packet.h"
#include "ssh.h"
@ -19,7 +19,7 @@ RCSID("$Id: auth-passwd.c,v 1.14 1999/12/29 12:47:46 markus Exp $");
* Tries to authenticate the user using password. Returns true if
* authentication succeeds.
*/
int
int
auth_password(struct passwd * pw, const char *password)
{
extern ServerOptions options;

View File

@ -1,21 +1,21 @@
/*
*
*
* auth-rh-rsa.c
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Sun May 7 03:08:06 1995 ylo
*
*
* Rhosts or /etc/hosts.equiv authentication combined with RSA host
* authentication.
*
*/
#include "includes.h"
RCSID("$Id: auth-rh-rsa.c,v 1.11 2000/03/23 22:15:33 markus Exp $");
RCSID("$Id: auth-rh-rsa.c,v 1.13 2000/04/14 10:30:29 markus Exp $");
#include "packet.h"
#include "ssh.h"
@ -23,8 +23,8 @@ RCSID("$Id: auth-rh-rsa.c,v 1.11 2000/03/23 22:15:33 markus Exp $");
#include "uidswap.h"
#include "servconf.h"
#include <ssl/rsa.h>
#include <ssl/dsa.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include "key.h"
#include "hostfile.h"
@ -33,7 +33,7 @@ RCSID("$Id: auth-rh-rsa.c,v 1.11 2000/03/23 22:15:33 markus Exp $");
* its host key. Returns true if authentication succeeds.
*/
int
int
auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key)
{
extern ServerOptions options;

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,22 +1,22 @@
/*
*
*
* auth-rsa.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 27 01:46:52 1995 ylo
*
*
* RSA-based authentication. This code determines whether to admit a login
* based on RSA authentication. This file also contains functions to check
* validity of the host key.
*
*
*/
#include "includes.h"
RCSID("$Id: auth-rsa.c,v 1.19 2000/03/23 22:15:33 markus Exp $");
RCSID("$Id: auth-rsa.c,v 1.23 2000/04/29 18:11:51 markus Exp $");
#include "rsa.h"
#include "packet.h"
@ -27,8 +27,8 @@ RCSID("$Id: auth-rsa.c,v 1.19 2000/03/23 22:15:33 markus Exp $");
#include "match.h"
#include "servconf.h"
#include <ssl/rsa.h>
#include <ssl/md5.h>
#include <openssl/rsa.h>
#include <openssl/md5.h>
/* Flags that may be set in authorized_keys options. */
extern int no_port_forwarding_flag;
@ -185,6 +185,7 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
}
}
if (fail) {
fclose(f);
log(buf);
packet_send_debug(buf);
restore_uid();
@ -238,7 +239,7 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
debug("%.100s, line %lu: bad key syntax",
SSH_USER_PERMITTED_KEYS, linenum);
packet_send_debug("%.100s, line %lu: bad key syntax",
SSH_USER_PERMITTED_KEYS, linenum);
SSH_USER_PERMITTED_KEYS, linenum);
continue;
}
/* cp now points to the comment part. */
@ -255,7 +256,6 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
/* We have found the desired key. */
/* Perform the challenge-response dialog for this key. */
if (!auth_rsa_challenge_dialog(pk)) {
/* Wrong response. */

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,20 +1,20 @@
/*
*
*
* authfd.c
*
*
* 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:30:28 1995 ylo
*
*
* Functions for connecting the local authentication agent.
*
*
*/
#include "includes.h"
RCSID("$Id: authfd.c,v 1.16 1999/12/15 19:43:10 markus Exp $");
RCSID("$Id: authfd.c,v 1.19 2000/04/29 18:11:52 markus Exp $");
#include "ssh.h"
#include "rsa.h"
@ -24,7 +24,7 @@ RCSID("$Id: authfd.c,v 1.16 1999/12/15 19:43:10 markus Exp $");
#include "xmalloc.h"
#include "getput.h"
#include <ssl/rsa.h>
#include <openssl/rsa.h>
/* Returns the number of the authentication fd, or -1 if there is none. */
@ -64,7 +64,7 @@ ssh_get_authentication_socket()
* ssh_get_authentication_socket().
*/
void
void
ssh_close_authentication_socket(int sock)
{
if (getenv(SSH_AUTHSOCKET_ENV_NAME))
@ -108,7 +108,7 @@ ssh_get_authentication_connection()
* memory.
*/
void
void
ssh_close_authentication_connection(AuthenticationConnection *ac)
{
buffer_free(&ac->packet);
@ -217,8 +217,8 @@ ssh_get_next_identity(AuthenticationConnection *auth,
*comment = buffer_get_string(&auth->identities, NULL);
if (bits != BN_num_bits(n))
error("Warning: identity keysize mismatch: actual %d, announced %u",
BN_num_bits(n), bits);
log("Warning: identity keysize mismatch: actual %d, announced %u",
BN_num_bits(n), bits);
/* Decrement the number of remaining entries. */
auth->howmany--;
@ -338,7 +338,7 @@ ssh_decrypt_challenge(AuthenticationConnection *auth,
* be used by normal applications.
*/
int
int
ssh_add_identity(AuthenticationConnection *auth,
RSA * key, const char *comment)
{
@ -426,7 +426,7 @@ ssh_add_identity(AuthenticationConnection *auth,
* meant to be used by normal applications.
*/
int
int
ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
{
Buffer buffer;
@ -509,7 +509,7 @@ ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
* by normal applications.
*/
int
int
ssh_remove_all_identities(AuthenticationConnection *auth)
{
Buffer buffer;

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);

View File

@ -1,28 +1,34 @@
/*
*
*
* authfile.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 27 03:52:05 1995 ylo
*
*
* This file contains functions for reading and writing identity files, and
* for reading the passphrase from the user.
*
*
*/
#include "includes.h"
RCSID("$Id: authfile.c,v 1.11 1999/12/06 19:11:15 deraadt Exp $");
RCSID("$Id: authfile.c,v 1.16 2000/04/26 21:28:32 markus Exp $");
#include <openssl/bn.h>
#include <openssl/dsa.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <ssl/bn.h>
#include "xmalloc.h"
#include "buffer.h"
#include "bufaux.h"
#include "cipher.h"
#include "ssh.h"
#include "key.h"
/* Version identification string for identity files. */
#define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n"
@ -35,8 +41,8 @@ RCSID("$Id: authfile.c,v 1.11 1999/12/06 19:11:15 deraadt Exp $");
*/
int
save_private_key(const char *filename, const char *passphrase,
RSA *key, const char *comment)
save_private_key_rsa(const char *filename, const char *passphrase,
RSA *key, const char *comment)
{
Buffer buffer, encrypted;
char buf[100], *cp;
@ -101,7 +107,7 @@ save_private_key(const char *filename, const char *passphrase,
/* Allocate space for the private part of the key in the buffer. */
buffer_append_space(&encrypted, &cp, buffer_len(&buffer));
cipher_set_key_string(&cipher, cipher_type, passphrase, 1);
cipher_set_key_string(&cipher, cipher_type, passphrase);
cipher_encrypt(&cipher, (unsigned char *) cp,
(unsigned char *) buffer_ptr(&buffer),
buffer_len(&buffer));
@ -128,6 +134,63 @@ save_private_key(const char *filename, const char *passphrase,
return 1;
}
/* save DSA key in OpenSSL PEM format */
int
save_private_key_dsa(const char *filename, const char *passphrase,
DSA *dsa, const char *comment)
{
FILE *fp;
int fd;
int success = 1;
int len = strlen(passphrase);
if (len > 0 && len <= 4) {
error("passphrase too short: %d bytes", len);
errno = 0;
return 0;
}
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0) {
debug("open %s failed", filename);
return 0;
}
fp = fdopen(fd, "w");
if (fp == NULL ) {
debug("fdopen %s failed", filename);
close(fd);
return 0;
}
if (len > 0) {
if (!PEM_write_DSAPrivateKey(fp, dsa, EVP_des_ede3_cbc(),
(char *)passphrase, strlen(passphrase), NULL, NULL))
success = 0;
} else {
if (!PEM_write_DSAPrivateKey(fp, dsa, NULL,
NULL, 0, NULL, NULL))
success = 0;
}
fclose(fp);
return success;
}
int
save_private_key(const char *filename, const char *passphrase, Key *key,
const char *comment)
{
switch (key->type) {
case KEY_RSA:
return save_private_key_rsa(filename, passphrase, key->rsa, comment);
break;
case KEY_DSA:
return save_private_key_dsa(filename, passphrase, key->dsa, comment);
break;
default:
break;
}
return 0;
}
/*
* Loads the public part of the key file. Returns 0 if an error was
* encountered (the file does not exist or is not readable), and non-zero
@ -135,8 +198,7 @@ save_private_key(const char *filename, const char *passphrase,
*/
int
load_public_key(const char *filename, RSA * pub,
char **comment_return)
load_public_key_rsa(const char *filename, RSA * pub, char **comment_return)
{
int fd, i;
off_t len;
@ -154,7 +216,7 @@ load_public_key(const char *filename, RSA * pub,
if (read(fd, cp, (size_t) len) != (size_t) len) {
debug("Read from key file %.200s failed: %.100s", filename,
strerror(errno));
strerror(errno));
buffer_free(&buffer);
close(fd);
return 0;
@ -183,9 +245,13 @@ load_public_key(const char *filename, RSA * pub,
/* Read the public key from the buffer. */
buffer_get_int(&buffer);
pub->n = BN_new();
/* XXX alloc */
if (pub->n == NULL)
pub->n = BN_new();
buffer_get_bignum(&buffer, pub->n);
pub->e = BN_new();
/* XXX alloc */
if (pub->e == NULL)
pub->e = BN_new();
buffer_get_bignum(&buffer, pub->e);
if (comment_return)
*comment_return = buffer_get_string(&buffer, NULL);
@ -196,6 +262,20 @@ load_public_key(const char *filename, RSA * pub,
return 1;
}
int
load_public_key(const char *filename, Key * key, char **comment_return)
{
switch (key->type) {
case KEY_RSA:
return load_public_key_rsa(filename, key->rsa, comment_return);
break;
case KEY_DSA:
default:
break;
}
return 0;
}
/*
* 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
@ -204,35 +284,17 @@ load_public_key(const char *filename, RSA * pub,
*/
int
load_private_key(const char *filename, const char *passphrase,
RSA * prv, char **comment_return)
load_private_key_rsa(int fd, const char *filename,
const char *passphrase, RSA * prv, char **comment_return)
{
int fd, i, check1, check2, cipher_type;
int i, check1, check2, cipher_type;
off_t len;
Buffer buffer, decrypted;
char *cp;
CipherContext cipher;
BN_CTX *ctx;
BIGNUM *aux;
struct stat st;
fd = open(filename, O_RDONLY);
if (fd < 0)
return 0;
/* check owner and modes */
if (fstat(fd, &st) < 0 ||
(st.st_uid != 0 && st.st_uid != getuid()) ||
(st.st_mode & 077) != 0) {
close(fd);
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("Bad ownership or mode(0%3.3o) for '%s'.",
st.st_mode & 0777, filename);
error("It is recommended that your private key files are NOT accessible by others.");
return 0;
}
len = lseek(fd, (off_t) 0, SEEK_END);
lseek(fd, (off_t) 0, SEEK_SET);
@ -280,7 +342,7 @@ load_private_key(const char *filename, const char *passphrase,
xfree(buffer_get_string(&buffer, NULL));
/* Check that it is a supported cipher. */
if (((cipher_mask() | SSH_CIPHER_NONE | SSH_AUTHFILE_CIPHER) &
if (((cipher_mask1() | SSH_CIPHER_NONE | SSH_AUTHFILE_CIPHER) &
(1 << cipher_type)) == 0) {
debug("Unsupported cipher %.100s used in key file %.200s.",
cipher_name(cipher_type), filename);
@ -292,7 +354,7 @@ load_private_key(const char *filename, const char *passphrase,
buffer_append_space(&decrypted, &cp, buffer_len(&buffer));
/* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
cipher_set_key_string(&cipher, cipher_type, passphrase, 0);
cipher_set_key_string(&cipher, cipher_type, passphrase);
cipher_decrypt(&cipher, (unsigned char *) cp,
(unsigned char *) buffer_ptr(&buffer),
buffer_len(&buffer));
@ -309,7 +371,9 @@ load_private_key(const char *filename, const char *passphrase,
buffer_free(&decrypted);
fail:
BN_clear_free(prv->n);
prv->n = NULL;
BN_clear_free(prv->e);
prv->e = NULL;
if (comment_return)
xfree(*comment_return);
return 0;
@ -343,3 +407,87 @@ load_private_key(const char *filename, const char *passphrase,
return 1;
}
int
load_private_key_dsa(int fd, const char *passphrase, Key *k, char **comment_return)
{
DSA *dsa;
BIO *in;
FILE *fp;
in = BIO_new(BIO_s_file());
if (in == NULL) {
error("BIO_new failed");
return 0;
}
fp = fdopen(fd, "r");
if (fp == NULL) {
error("fdopen failed");
return 0;
}
BIO_set_fp(in, fp, BIO_NOCLOSE);
dsa = PEM_read_bio_DSAPrivateKey(in, NULL, NULL, (char *)passphrase);
if (dsa == NULL) {
debug("PEM_read_bio_DSAPrivateKey failed");
} else {
/* replace k->dsa with loaded key */
DSA_free(k->dsa);
k->dsa = dsa;
}
BIO_free(in);
fclose(fp);
if (comment_return)
*comment_return = xstrdup("dsa w/o comment");
debug("read DSA private key done");
#ifdef DEBUG_DSS
DSA_print_fp(stderr, dsa, 8);
#endif
return dsa != NULL ? 1 : 0;
}
int
load_private_key(const char *filename, const char *passphrase, Key *key,
char **comment_return)
{
int fd;
int ret = 0;
struct stat st;
fd = open(filename, O_RDONLY);
if (fd < 0)
return 0;
/* check owner and modes */
if (fstat(fd, &st) < 0 ||
(st.st_uid != 0 && st.st_uid != getuid()) ||
(st.st_mode & 077) != 0) {
close(fd);
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("Bad ownership or mode(0%3.3o) for '%s'.",
st.st_mode & 0777, filename);
error("It is recommended that your private key files are NOT accessible by others.");
return 0;
}
switch (key->type) {
case KEY_RSA:
if (key->rsa->e != NULL) {
BN_clear_free(key->rsa->e);
key->rsa->e = NULL;
}
if (key->rsa->n != NULL) {
BN_clear_free(key->rsa->n);
key->rsa->n = NULL;
}
ret = load_private_key_rsa(fd, filename, passphrase,
key->rsa, comment_return);
break;
case KEY_DSA:
ret = load_private_key_dsa(fd, passphrase, key, comment_return);
default:
break;
}
close(fd);
return ret;
}

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,24 +1,26 @@
/*
*
*
* bufaux.c
*
*
* 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:24:47 1995 ylo
*
*
* Auxiliary functions for storing and retrieving various data types to/from
* Buffers.
*
* SSH2 packet format added by Markus Friedl
*
*/
#include "includes.h"
RCSID("$Id: bufaux.c,v 1.8 2000/03/16 20:56:14 markus Exp $");
RCSID("$Id: bufaux.c,v 1.11 2000/04/14 10:30:30 markus Exp $");
#include "ssh.h"
#include <ssl/bn.h>
#include <openssl/bn.h>
#include "bufaux.h"
#include "xmalloc.h"
#include "getput.h"
@ -75,10 +77,54 @@ buffer_get_bignum(Buffer *buffer, BIGNUM *value)
return 2 + bytes;
}
/*
* Stores an BIGNUM in the buffer in SSH2 format.
*/
void
buffer_put_bignum2(Buffer *buffer, BIGNUM *value)
{
int bytes = BN_num_bytes(value) + 1;
unsigned char *buf = xmalloc(bytes);
int oi;
int hasnohigh = 0;
buf[0] = '\0';
/* Get the value of in binary */
oi = BN_bn2bin(value, buf+1);
if (oi != bytes-1)
fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
oi, bytes);
hasnohigh = (buf[1] & 0x80) ? 0 : 1;
if (value->neg) {
/**XXX should be two's-complement */
int i, carry;
unsigned char *uc = buf;
log("negativ!");
for(i = bytes-1, carry = 1; i>=0; i--) {
uc[i] ^= 0xff;
if(carry)
carry = !++uc[i];
}
}
buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh);
memset(buf, 0, bytes);
xfree(buf);
}
int
buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
{
/**XXX should be two's-complement */
int len;
unsigned char *bin = (unsigned char *)buffer_get_string(buffer, (unsigned int *)&len);
BN_bin2bn(bin, len, value);
xfree(bin);
return len;
}
/*
* Returns an integer from the buffer (4 bytes, msb first).
*/
unsigned int
unsigned int
buffer_get_int(Buffer *buffer)
{
unsigned char buf[4];
@ -89,7 +135,7 @@ buffer_get_int(Buffer *buffer)
/*
* Stores an integer in the buffer in 4 bytes, msb first.
*/
void
void
buffer_put_int(Buffer *buffer, unsigned int value)
{
char buf[4];
@ -129,17 +175,22 @@ buffer_get_string(Buffer *buffer, unsigned int *length_ptr)
/*
* Stores and arbitrary binary string in the buffer.
*/
void
void
buffer_put_string(Buffer *buffer, const void *buf, unsigned int len)
{
buffer_put_int(buffer, len);
buffer_append(buffer, buf, len);
}
void
buffer_put_cstring(Buffer *buffer, const char *s)
{
buffer_put_string(buffer, s, strlen(s));
}
/*
* Returns a character from the buffer (0 - 255).
*/
int
int
buffer_get_char(Buffer *buffer)
{
char ch;
@ -150,7 +201,7 @@ buffer_get_char(Buffer *buffer)
/*
* Stores a character in the buffer.
*/
void
void
buffer_put_char(Buffer *buffer, int value)
{
char ch = value;

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,26 +1,29 @@
/*
*
*
* cipher.c
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Wed Apr 19 17:41:39 1995 ylo
*
*
*/
#include "includes.h"
RCSID("$Id: cipher.c,v 1.20 2000/03/22 09:55:10 markus Exp $");
RCSID("$Id: cipher.c,v 1.26 2000/04/14 10:30:30 markus Exp $");
#include "ssh.h"
#include "cipher.h"
#include "xmalloc.h"
#include <ssl/md5.h>
#include <openssl/md5.h>
/*
* What kind of tripple DES are these 2 routines?
* This is used by SSH1:
*
* What kind of triple DES are these 2 routines?
*
* Why is there a redundant initialization vector?
*
@ -75,7 +78,7 @@ SSH_3CBC_DECRYPT(des_key_schedule ks1,
}
/*
* SSH uses a variation on Blowfish, all bytes must be swapped before
* SSH1 uses a variation on Blowfish, all bytes must be swapped before
* and after encryption/decryption. Thus the swap_bytes stuff (yuk).
*/
static void
@ -116,7 +119,12 @@ static char *cipher_names[] =
"3des",
"tss",
"rc4",
"blowfish"
"blowfish",
"reserved",
"blowfish-cbc",
"3des-cbc",
"arcfour",
"cast128-cbc"
};
/*
@ -125,14 +133,29 @@ static char *cipher_names[] =
* supported cipher.
*/
unsigned int
cipher_mask()
unsigned int
cipher_mask1()
{
unsigned int mask = 0;
mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
mask |= 1 << SSH_CIPHER_BLOWFISH;
return mask;
}
unsigned int
cipher_mask2()
{
unsigned int mask = 0;
mask |= 1 << SSH_CIPHER_BLOWFISH_CBC;
mask |= 1 << SSH_CIPHER_3DES_CBC;
mask |= 1 << SSH_CIPHER_ARCFOUR;
mask |= 1 << SSH_CIPHER_CAST128_CBC;
return mask;
}
unsigned int
cipher_mask()
{
return cipher_mask1() | cipher_mask2();
}
/* Returns the name of the cipher. */
@ -141,10 +164,34 @@ cipher_name(int cipher)
{
if (cipher < 0 || cipher >= sizeof(cipher_names) / sizeof(cipher_names[0]) ||
cipher_names[cipher] == NULL)
fatal("cipher_name: bad cipher number: %d", cipher);
fatal("cipher_name: bad cipher name: %d", cipher);
return cipher_names[cipher];
}
/* Returns 1 if the name of the ciphers are valid. */
#define CIPHER_SEP ","
int
ciphers_valid(const char *names)
{
char *ciphers;
char *p;
int i;
if (strcmp(names, "") == 0)
return 0;
ciphers = xstrdup(names);
for ((p = strtok(ciphers, CIPHER_SEP)); p; (p = strtok(NULL, CIPHER_SEP))) {
i = cipher_number(p);
if (i == -1 || !(cipher_mask2() & (1 << i))) {
xfree(ciphers);
return 0;
}
}
xfree(ciphers);
return 1;
}
/*
* Parses the name of the cipher. Returns the number of the corresponding
* cipher, or -1 on error.
@ -166,9 +213,8 @@ cipher_number(const char *name)
* passphrase and using the resulting 16 bytes as the key.
*/
void
cipher_set_key_string(CipherContext *context, int cipher,
const char *passphrase, int for_encryption)
void
cipher_set_key_string(CipherContext *context, int cipher, const char *passphrase)
{
MD5_CTX md;
unsigned char digest[16];
@ -177,7 +223,7 @@ cipher_set_key_string(CipherContext *context, int cipher,
MD5_Update(&md, (const unsigned char *) passphrase, strlen(passphrase));
MD5_Final(digest, &md);
cipher_set_key(context, cipher, digest, 16, for_encryption);
cipher_set_key(context, cipher, digest, 16);
memset(digest, 0, sizeof(digest));
memset(&md, 0, sizeof(md));
@ -185,9 +231,9 @@ cipher_set_key_string(CipherContext *context, int cipher,
/* Selects the cipher to use and sets the key. */
void
cipher_set_key(CipherContext *context, int cipher,
const unsigned char *key, int keylen, int for_encryption)
void
cipher_set_key(CipherContext *context, int cipher, const unsigned char *key,
int keylen)
{
unsigned char padded[32];
@ -227,19 +273,86 @@ cipher_set_key(CipherContext *context, int cipher,
break;
case SSH_CIPHER_BLOWFISH:
if (keylen < 16)
error("Key length %d is insufficient for blowfish.", keylen);
BF_set_key(&context->u.bf.key, keylen, padded);
memset(context->u.bf.iv, 0, 8);
break;
case SSH_CIPHER_3DES_CBC:
case SSH_CIPHER_BLOWFISH_CBC:
case SSH_CIPHER_ARCFOUR:
case SSH_CIPHER_CAST128_CBC:
fatal("cipher_set_key: illegal cipher: %s", cipher_name(cipher));
break;
default:
fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher));
}
memset(padded, 0, sizeof(padded));
}
void
cipher_set_key_iv(CipherContext * context, int cipher,
const unsigned char *key, int keylen,
const unsigned char *iv, int ivlen)
{
/* Set cipher type. */
context->type = cipher;
/* Initialize the initialization vector. */
switch (cipher) {
case SSH_CIPHER_NONE:
break;
case SSH_CIPHER_3DES:
case SSH_CIPHER_BLOWFISH:
fatal("cipher_set_key_iv: illegal cipher: %s", cipher_name(cipher));
break;
case SSH_CIPHER_3DES_CBC:
if (keylen < 24)
error("Key length %d is insufficient for 3des-cbc.", keylen);
des_set_key((void *) key, context->u.des3.key1);
des_set_key((void *) (key+8), context->u.des3.key2);
des_set_key((void *) (key+16), context->u.des3.key3);
if (ivlen < 8)
error("IV length %d is insufficient for 3des-cbc.", ivlen);
memcpy(context->u.des3.iv3, (char *)iv, 8);
break;
case SSH_CIPHER_BLOWFISH_CBC:
if (keylen < 16)
error("Key length %d is insufficient for blowfish.", keylen);
if (ivlen < 8)
error("IV length %d is insufficient for blowfish.", ivlen);
BF_set_key(&context->u.bf.key, keylen, (unsigned char *)key);
memcpy(context->u.bf.iv, (char *)iv, 8);
break;
case SSH_CIPHER_ARCFOUR:
if (keylen < 16)
error("Key length %d is insufficient for arcfour.", keylen);
RC4_set_key(&context->u.rc4, keylen, (unsigned char *)key);
break;
case SSH_CIPHER_CAST128_CBC:
if (keylen < 16)
error("Key length %d is insufficient for cast128.", keylen);
if (ivlen < 8)
error("IV length %d is insufficient for cast128.", ivlen);
CAST_set_key(&context->u.cast.key, keylen, (unsigned char *) key);
memcpy(context->u.cast.iv, (char *)iv, 8);
break;
default:
fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher));
}
}
/* Encrypts data using the cipher. */
void
void
cipher_encrypt(CipherContext *context, unsigned char *dest,
const unsigned char *src, unsigned int len)
{
@ -261,11 +374,32 @@ cipher_encrypt(CipherContext *context, unsigned char *dest,
case SSH_CIPHER_BLOWFISH:
swap_bytes(src, dest, len);
BF_cbc_encrypt(dest, dest, len,
&context->u.bf.key, context->u.bf.iv,
&context->u.bf.key, context->u.bf.iv,
BF_ENCRYPT);
swap_bytes(dest, dest, len);
break;
case SSH_CIPHER_BLOWFISH_CBC:
BF_cbc_encrypt((void *)src, dest, len,
&context->u.bf.key, context->u.bf.iv,
BF_ENCRYPT);
break;
case SSH_CIPHER_3DES_CBC:
des_ede3_cbc_encrypt(src, dest, len,
context->u.des3.key1, context->u.des3.key2,
context->u.des3.key3, &context->u.des3.iv3, DES_ENCRYPT);
break;
case SSH_CIPHER_ARCFOUR:
RC4(&context->u.rc4, len, (unsigned char *)src, dest);
break;
case SSH_CIPHER_CAST128_CBC:
CAST_cbc_encrypt(src, dest, len,
&context->u.cast.key, context->u.cast.iv, CAST_ENCRYPT);
break;
default:
fatal("cipher_encrypt: unknown cipher: %s", cipher_name(context->type));
}
@ -273,7 +407,7 @@ cipher_encrypt(CipherContext *context, unsigned char *dest,
/* Decrypts data using the cipher. */
void
void
cipher_decrypt(CipherContext *context, unsigned char *dest,
const unsigned char *src, unsigned int len)
{
@ -300,6 +434,27 @@ cipher_decrypt(CipherContext *context, unsigned char *dest,
swap_bytes(dest, dest, len);
break;
case SSH_CIPHER_BLOWFISH_CBC:
BF_cbc_encrypt((void *) src, dest, len,
&context->u.bf.key, context->u.bf.iv,
BF_DECRYPT);
break;
case SSH_CIPHER_3DES_CBC:
des_ede3_cbc_encrypt(src, dest, len,
context->u.des3.key1, context->u.des3.key2,
context->u.des3.key3, &context->u.des3.iv3, DES_DECRYPT);
break;
case SSH_CIPHER_ARCFOUR:
RC4(&context->u.rc4, len, (unsigned char *)src, dest);
break;
case SSH_CIPHER_CAST128_CBC:
CAST_cbc_encrypt(src, dest, len,
&context->u.cast.key, context->u.cast.iv, CAST_DECRYPT);
break;
default:
fatal("cipher_decrypt: unknown cipher: %s", cipher_name(context->type));
}

View File

@ -1,26 +1,29 @@
/*
*
*
* cipher.h
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Wed Apr 19 16:50:42 1995 ylo
*
*
*/
/* RCSID("$Id: cipher.h,v 1.11 2000/03/22 09:55:10 markus Exp $"); */
/* RCSID("$Id: cipher.h,v 1.17 2000/05/08 17:12:15 markus Exp $"); */
#ifndef CIPHER_H
#define CIPHER_H
#include <ssl/des.h>
#include <ssl/blowfish.h>
#include <openssl/des.h>
#include <openssl/blowfish.h>
#include <openssl/rc4.h>
#include <openssl/cast.h>
/* Cipher types. New types can be added, but old types should not be removed
for compatibility. The maximum allowed value is 31. */
#define SSH_CIPHER_ILLEGAL -2 /* No valid cipher selected. */
#define SSH_CIPHER_NOT_SET -1 /* None selected (invalid number). */
#define SSH_CIPHER_NONE 0 /* no encryption */
#define SSH_CIPHER_IDEA 1 /* IDEA CFB */
@ -29,6 +32,13 @@
#define SSH_CIPHER_BROKEN_TSS 4 /* TRI's Simple Stream encryption CBC */
#define SSH_CIPHER_BROKEN_RC4 5 /* Alleged RC4 */
#define SSH_CIPHER_BLOWFISH 6
#define SSH_CIPHER_RESERVED 7
/* these ciphers are used in SSH2: */
#define SSH_CIPHER_BLOWFISH_CBC 8
#define SSH_CIPHER_3DES_CBC 9
#define SSH_CIPHER_ARCFOUR 10 /* Alleged RC4 */
#define SSH_CIPHER_CAST128_CBC 11
typedef struct {
unsigned int type;
@ -44,6 +54,11 @@ typedef struct {
struct bf_key_st key;
unsigned char iv[8];
} bf;
struct {
CAST_KEY key;
unsigned char iv[8];
} cast;
RC4_KEY rc4;
} u;
} CipherContext;
/*
@ -52,6 +67,8 @@ typedef struct {
* supported cipher.
*/
unsigned int cipher_mask();
unsigned int cipher_mask1();
unsigned int cipher_mask2();
/* Returns the name of the cipher. */
const char *cipher_name(int cipher);
@ -62,29 +79,36 @@ const char *cipher_name(int cipher);
*/
int cipher_number(const char *name);
/* returns 1 if all ciphers are supported (ssh2 only) */
int ciphers_valid(const char *names);
/*
* Selects the cipher to use and sets the key. If for_encryption is true,
* the key is setup for encryption; otherwise it is setup for decryption.
*/
void
void
cipher_set_key(CipherContext * context, int cipher,
const unsigned char *key, int keylen, int for_encryption);
const unsigned char *key, int keylen);
void
cipher_set_key_iv(CipherContext * context, int cipher,
const unsigned char *key, int keylen,
const unsigned char *iv, int ivlen);
/*
* Sets key for the cipher by computing the MD5 checksum of the passphrase,
* and using the resulting 16 bytes as the key.
*/
void
void
cipher_set_key_string(CipherContext * context, int cipher,
const char *passphrase, int for_encryption);
const char *passphrase);
/* Encrypts data using the cipher. */
void
void
cipher_encrypt(CipherContext * context, unsigned char *dest,
const unsigned char *src, unsigned int len);
/* Decrypts data using the cipher. */
void
void
cipher_decrypt(CipherContext * context, unsigned char *dest,
const unsigned char *src, unsigned int len);

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

@ -28,11 +28,11 @@
*/
#include "includes.h"
RCSID("$Id: fingerprint.c,v 1.5 2000/03/16 20:56:14 markus Exp $");
RCSID("$Id: fingerprint.c,v 1.6 2000/04/12 09:39:10 markus Exp $");
#include "ssh.h"
#include "xmalloc.h"
#include <ssl/md5.h>
#include <openssl/md5.h>
#define FPRINT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"

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

@ -1,26 +1,26 @@
/*
*
*
* hostfile.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 29 07:10:56 1995 ylo
*
*
* Functions for manipulating the known hosts files.
*
*
*/
#include "includes.h"
RCSID("$OpenBSD: hostfile.c,v 1.14 2000/03/23 22:15:33 markus Exp $");
RCSID("$OpenBSD: hostfile.c,v 1.18 2000/04/29 18:11:52 markus Exp $");
#include "packet.h"
#include "match.h"
#include "ssh.h"
#include <ssl/rsa.h>
#include <ssl/dsa.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include "key.h"
#include "hostfile.h"
@ -39,13 +39,8 @@ hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret)
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
;
/* Get number of bits. */
if (*cp < '0' || *cp > '9')
return 0; /* Bad bit count... */
for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
bits = 10 * bits + *cp - '0';
if (!key_read(ret, bits, &cp))
bits = key_read(ret, &cp);
if (bits == 0)
return 0;
/* Skip trailing whitespace. */
@ -75,10 +70,10 @@ hostfile_check_key(int bits, Key *key, const char *host, const char *filename, i
if (key == NULL || key->type != KEY_RSA || key->rsa == NULL)
return 1;
if (bits != BN_num_bits(key->rsa->n)) {
error("Warning: %s, line %d: keysize mismatch for host %s: "
log("Warning: %s, line %d: keysize mismatch for host %s: "
"actual %d vs. announced %d.",
filename, linenum, host, BN_num_bits(key->rsa->n), bits);
error("Warning: replace %d with %d in %s, line %d.",
log("Warning: replace %d with %d in %s, line %d.",
bits, BN_num_bits(key->rsa->n), filename, linenum);
}
return 1;
@ -182,24 +177,18 @@ add_host_to_hostfile(const char *filename, const char *host, Key *key)
{
FILE *f;
int success = 0;
if (key == NULL)
return 1;
/* Open the file for appending. */
return 1; /* XXX ? */
f = fopen(filename, "a");
if (!f)
return 0;
fprintf(f, "%s ", host);
if (key_write(key, f)) {
fprintf(f, "\n");
success = 1;
} else {
error("add_host_to_hostfile: saving key failed");
error("add_host_to_hostfile: saving key in %s failed", filename);
}
/* Close the file. */
fprintf(f, "\n");
fclose(f);
return success;
}

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);
/*

View File

@ -1,16 +1,16 @@
/*
*
*
* includes.h
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Thu Mar 23 16:29:37 1995 ylo
*
*
* This file includes most of the needed system headers.
*
*
*/
#ifndef INCLUDES_H

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

@ -33,11 +33,15 @@
#include "includes.h"
#include "ssh.h"
#include <ssl/rsa.h>
#include <ssl/dsa.h>
#include <ssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/evp.h>
#include "xmalloc.h"
#include "key.h"
#include "dsa.h"
#include "uuencode.h"
#define SSH_DSS "ssh-dss"
Key *
key_new(int type)
@ -47,6 +51,8 @@ key_new(int type)
DSA *dsa;
k = xmalloc(sizeof(*k));
k->type = type;
k->dsa = NULL;
k->rsa = NULL;
switch (k->type) {
case KEY_RSA:
rsa = RSA_new();
@ -63,8 +69,6 @@ key_new(int type)
k->dsa = dsa;
break;
case KEY_EMPTY:
k->dsa = NULL;
k->rsa = NULL;
break;
default:
fatal("key_new: bad key type %d", k->type);
@ -111,7 +115,7 @@ key_equal(Key *a, Key *b)
BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
break;
default:
fatal("key_free: bad key type %d", a->type);
fatal("key_equal: bad key type %d", a->type);
break;
}
return 0;
@ -127,46 +131,37 @@ char *
key_fingerprint(Key *k)
{
static char retval[80];
unsigned char *buf = NULL;
unsigned char *blob = NULL;
int len = 0;
int nlen, elen, plen, qlen, glen, publen;
int nlen, elen;
switch (k->type) {
case KEY_RSA:
nlen = BN_num_bytes(k->rsa->n);
elen = BN_num_bytes(k->rsa->e);
len = nlen + elen;
buf = xmalloc(len);
BN_bn2bin(k->rsa->n, buf);
BN_bn2bin(k->rsa->e, buf + nlen);
blob = xmalloc(len);
BN_bn2bin(k->rsa->n, blob);
BN_bn2bin(k->rsa->e, blob + nlen);
break;
case KEY_DSA:
plen = BN_num_bytes(k->dsa->p);
qlen = BN_num_bytes(k->dsa->q);
glen = BN_num_bytes(k->dsa->g);
publen = BN_num_bytes(k->dsa->pub_key);
len = qlen + qlen + glen + publen;
buf = xmalloc(len);
BN_bn2bin(k->dsa->p, buf);
BN_bn2bin(k->dsa->q, buf + plen);
BN_bn2bin(k->dsa->g, buf + plen + qlen);
BN_bn2bin(k->dsa->pub_key , buf + plen + qlen + glen);
dsa_make_key_blob(k, &blob, &len);
break;
default:
fatal("key_fingerprint: bad key type %d", k->type);
break;
}
if (buf != NULL) {
if (blob != NULL) {
unsigned char d[16];
EVP_MD_CTX md;
EVP_DigestInit(&md, EVP_md5());
EVP_DigestUpdate(&md, buf, len);
EVP_DigestUpdate(&md, blob, len);
EVP_DigestFinal(&md, d, NULL);
snprintf(retval, sizeof(retval), FPRINT,
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
memset(buf, 0, len);
xfree(buf);
memset(blob, 0, len);
xfree(blob);
}
return retval;
}
@ -226,13 +221,27 @@ write_bignum(FILE *f, BIGNUM *num)
free(buf);
return 1;
}
int
key_read(Key *ret, unsigned int bits, char **cpp)
unsigned int
key_read(Key *ret, char **cpp)
{
Key *k;
unsigned int bits = 0;
char *cp;
int len, n;
unsigned char *blob;
cp = *cpp;
switch(ret->type) {
case KEY_RSA:
/* Get number of bits. */
if (*cp < '0' || *cp > '9')
return 0; /* Bad bit count... */
for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
bits = 10 * bits + *cp - '0';
if (bits == 0)
return 0;
*cpp = cp;
/* Get public exponent, public modulus. */
if (!read_bignum(cpp, ret->rsa->e))
return 0;
@ -240,22 +249,36 @@ key_read(Key *ret, unsigned int bits, char **cpp)
return 0;
break;
case KEY_DSA:
if (bits != 0)
if (strncmp(cp, SSH_DSS " ", 7) != 0)
return 0;
if (!read_bignum(cpp, ret->dsa->p))
cp += 7;
len = 2*strlen(cp);
blob = xmalloc(len);
n = uudecode(cp, blob, len);
if (n < 0) {
error("uudecode %s failed", cp);
return 0;
if (!read_bignum(cpp, ret->dsa->q))
return 0;
if (!read_bignum(cpp, ret->dsa->g))
return 0;
if (!read_bignum(cpp, ret->dsa->pub_key))
}
k = dsa_key_from_blob(blob, n);
if (k == NULL)
return 0;
xfree(blob);
if (ret->dsa != NULL)
DSA_free(ret->dsa);
ret->dsa = k->dsa;
k->dsa = NULL;
key_free(k);
bits = BN_num_bits(ret->dsa->p);
cp = strchr(cp, '=');
if (cp == NULL)
return 0;
*cpp = cp + 1;
break;
default:
fatal("bad key type: %d", ret->type);
fatal("key_read: bad key type: %d", ret->type);
break;
}
return 1;
return bits;
}
int
key_write(Key *key, FILE *f)
@ -274,17 +297,30 @@ key_write(Key *key, FILE *f)
error("key_write: failed for RSA key");
}
} else if (key->type == KEY_DSA && key->dsa != NULL) {
/* bits == 0 means DSA key */
bits = 0;
fprintf(f, "%u", bits);
if (write_bignum(f, key->dsa->p) &&
write_bignum(f, key->dsa->q) &&
write_bignum(f, key->dsa->g) &&
write_bignum(f, key->dsa->pub_key)) {
int len, n;
unsigned char *blob, *uu;
dsa_make_key_blob(key, &blob, &len);
uu = xmalloc(2*len);
n = uuencode(blob, len, uu, 2*len);
if (n > 0) {
fprintf(f, "%s %s", SSH_DSS, uu);
success = 1;
} else {
error("key_write: failed for DSA key");
}
xfree(blob);
xfree(uu);
}
return success;
}
char *
key_type(Key *k)
{
switch (k->type) {
case KEY_RSA:
return "RSA";
break;
case KEY_DSA:
return "DSA";
break;
}
return "unknown";
}

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,24 +1,24 @@
/*
*
*
* login.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 24 14:51:08 1995 ylo
*
*
* This file performs some of the things login(1) normally does. We cannot
* easily use something like login -p -h host -f user, because there are
* several different logins around, and it is hard to determined what kind of
* login the current system has. Also, we want to be able to execute commands
* on a tty.
*
*
*/
#include "includes.h"
RCSID("$Id: login.c,v 1.11 2000/01/04 00:07:59 markus Exp $");
RCSID("$Id: login.c,v 1.13 2000/04/19 07:05:49 deraadt Exp $");
#include <util.h>
#include <utmp.h>
@ -35,7 +35,7 @@ RCSID("$Id: login.c,v 1.11 2000/01/04 00:07:59 markus Exp $");
* is found). The name of the host used last time is returned in buf.
*/
unsigned long
unsigned long
get_last_login_time(uid_t uid, const char *logname,
char *buf, unsigned int bufsize)
{
@ -67,8 +67,8 @@ get_last_login_time(uid_t uid, const char *logname,
* were more standardized.
*/
void
record_login(int pid, const char *ttyname, const char *user, uid_t uid,
void
record_login(pid_t pid, const char *ttyname, const char *user, uid_t uid,
const char *host, struct sockaddr * addr)
{
int fd;
@ -115,8 +115,8 @@ record_login(int pid, const char *ttyname, const char *user, uid_t uid,
/* Records that the user has logged out. */
void
record_logout(int pid, const char *ttyname)
void
record_logout(pid_t pid, const char *ttyname)
{
const char *line = ttyname + 5; /* /dev/ttyq8 -> ttyq8 */
if (logout(line))

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,33 +1,33 @@
/*
*
*
* mpaux.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 16 04:29:30 1995 ylo
*
*
* This file contains various auxiliary functions related to multiple
* precision integers.
*
*
*/
#include "includes.h"
RCSID("$Id: mpaux.c,v 1.9 1999/12/08 22:37:42 markus Exp $");
RCSID("$Id: mpaux.c,v 1.12 2000/04/14 10:30:32 markus Exp $");
#include <ssl/bn.h>
#include <openssl/bn.h>
#include "getput.h"
#include "xmalloc.h"
#include <ssl/md5.h>
#include <openssl/md5.h>
void
compute_session_id(unsigned char session_id[16],
unsigned char cookie[8],
BIGNUM* host_key_n,
BIGNUM* session_key_n)
unsigned char cookie[8],
BIGNUM* host_key_n,
BIGNUM* session_key_n)
{
unsigned int host_key_bytes = BN_num_bytes(host_key_n);
unsigned int session_key_bytes = BN_num_bytes(session_key_n);

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,24 +1,24 @@
/*
*
*
* packet.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 02:02:14 1995 ylo
*
*
* Interface for the packet protocol functions.
*
*
*/
/* RCSID("$Id: packet.h,v 1.10 2000/03/16 20:56:14 markus Exp $"); */
/* RCSID("$Id: packet.h,v 1.15 2000/04/14 10:30:32 markus Exp $"); */
#ifndef PACKET_H
#define PACKET_H
#include <ssl/bn.h>
#include <openssl/bn.h>
/*
* Sets the socket used for communication. Disables encryption until
@ -47,7 +47,7 @@ void packet_close(void);
* key is used for both sending and reception. However, both directions are
* encrypted independently of each other. Cipher types are defined in ssh.h.
*/
void
void
packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
int cipher_type);
@ -83,9 +83,12 @@ void packet_put_int(unsigned int value);
/* Appends an arbitrary precision integer to packet data. */
void packet_put_bignum(BIGNUM * value);
void packet_put_bignum2(BIGNUM * value);
/* Appends a string to packet data. */
void packet_put_string(const char *buf, unsigned int len);
void packet_put_cstring(const char *str);
void packet_put_raw(const char *buf, unsigned int len);
/*
* Finalizes and sends the packet. If the encryption key has been set,
@ -129,6 +132,8 @@ unsigned int packet_get_int(void);
* must have been initialized before this call.
*/
void packet_get_bignum(BIGNUM * value, int *length_ptr);
void packet_get_bignum2(BIGNUM * value, int *length_ptr);
char *packet_get_raw(int *length_ptr);
/*
* Returns a string from the packet data. The string is allocated using
@ -191,8 +196,24 @@ do { \
} \
} while (0)
#define packet_done() \
do { \
int _len = packet_remaining(); \
if (_len > 0) { \
log("Packet integrity error (%d bytes remaining) at %s:%d", \
_len ,__FILE__, __LINE__); \
packet_disconnect("Packet integrity error."); \
} \
} while (0)
/* remote host is connected via a socket/ipv4 */
int packet_connection_is_on_socket(void);
int packet_connection_is_ipv4(void);
/* enable SSH2 packet format */
void packet_set_ssh2_format(void);
/* returns remaining payload bytes */
int packet_remaining(void);
#endif /* PACKET_H */

View File

@ -1,20 +1,20 @@
/*
*
*
* pty.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 04:37:25 1995 ylo
*
*
* Allocating a pseudo-terminal, and making it the controlling tty.
*
*
*/
#include "includes.h"
RCSID("$Id: pty.c,v 1.12 2000/02/15 16:52:58 markus Exp $");
RCSID("$Id: pty.c,v 1.13 2000/04/14 10:30:32 markus Exp $");
#include <util.h>
#include "pty.h"
@ -36,7 +36,7 @@ RCSID("$Id: pty.c,v 1.12 2000/02/15 16:52:58 markus Exp $");
* returned (the buffer must be able to hold at least 64 characters).
*/
int
int
pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
{
#if defined(HAVE_OPENPTY) || defined(BSD4_4)
@ -174,7 +174,7 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
/* Releases the tty. Its ownership is returned to root, and permissions to 0666. */
void
void
pty_release(const char *ttyname)
{
if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0)
@ -185,7 +185,7 @@ pty_release(const char *ttyname)
/* Makes the tty the processes controlling tty and sets it to sane modes. */
void
void
pty_make_controlling_tty(int *ttyfd, const char *ttyname)
{
int fd;
@ -238,7 +238,7 @@ 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,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

@ -1,25 +1,27 @@
/*
*
*
* readconf.c
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Sat Apr 22 00:03:10 1995 ylo
*
*
* Functions for reading the configuration files.
*
*
*/
#include "includes.h"
RCSID("$Id: readconf.c,v 1.23 2000/02/28 19:51:58 markus Exp $");
RCSID("$Id: readconf.c,v 1.31 2000/05/08 17:12:15 markus Exp $");
#include "ssh.h"
#include "cipher.h"
#include "readconf.h"
#include "match.h"
#include "xmalloc.h"
#include "compat.h"
/* Format of the configuration file:
@ -102,7 +104,8 @@ typedef enum {
oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
oUsePrivilegedPort, oLogLevel
oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oIdentityFile2,
oGlobalKnownHostsFile2, oUserKnownHostsFile2, oDSAAuthentication
} OpCodes;
/* Textual representations of the tokens. */
@ -118,6 +121,7 @@ static struct {
{ "rhostsauthentication", oRhostsAuthentication },
{ "passwordauthentication", oPasswordAuthentication },
{ "rsaauthentication", oRSAAuthentication },
{ "dsaauthentication", oDSAAuthentication },
{ "skeyauthentication", oSkeyAuthentication },
#ifdef KRB4
{ "kerberosauthentication", oKerberosAuthentication },
@ -129,10 +133,13 @@ static struct {
{ "fallbacktorsh", oFallBackToRsh },
{ "usersh", oUseRsh },
{ "identityfile", oIdentityFile },
{ "identityfile2", oIdentityFile2 },
{ "hostname", oHostName },
{ "proxycommand", oProxyCommand },
{ "port", oPort },
{ "cipher", oCipher },
{ "ciphers", oCiphers },
{ "protocol", oProtocol },
{ "remoteforward", oRemoteForward },
{ "localforward", oLocalForward },
{ "user", oUser },
@ -141,6 +148,8 @@ static struct {
{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
{ "globalknownhostsfile", oGlobalKnownHostsFile },
{ "userknownhostsfile", oUserKnownHostsFile },
{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
{ "userknownhostsfile2", oUserKnownHostsFile2 },
{ "connectionattempts", oConnectionAttempts },
{ "batchmode", oBatchMode },
{ "checkhostip", oCheckHostIP },
@ -163,7 +172,7 @@ static struct {
* error.
*/
void
void
add_local_forward(Options *options, u_short port, const char *host,
u_short host_port)
{
@ -184,7 +193,7 @@ add_local_forward(Options *options, u_short port, const char *host,
* an error.
*/
void
void
add_remote_forward(Options *options, u_short port, const char *host,
u_short host_port)
{
@ -203,7 +212,7 @@ add_remote_forward(Options *options, u_short port, const char *host,
* returns if the token is not known.
*/
static OpCodes
static OpCodes
parse_token(const char *cp, const char *filename, int linenum)
{
unsigned int i;
@ -282,6 +291,10 @@ process_config_line(Options *options, const char *host,
intptr = &options->password_authentication;
goto parse_flag;
case oDSAAuthentication:
intptr = &options->dsa_authentication;
goto parse_flag;
case oRSAAuthentication:
intptr = &options->rsa_authentication;
goto parse_flag;
@ -364,14 +377,22 @@ process_config_line(Options *options, const char *host,
goto parse_int;
case oIdentityFile:
case oIdentityFile2:
cp = strtok(NULL, WHITESPACE);
if (!cp)
fatal("%.200s line %d: Missing argument.", filename, linenum);
if (*activep) {
if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
intptr = (opcode == oIdentityFile) ?
&options->num_identity_files :
&options->num_identity_files2;
if (*intptr >= SSH_MAX_IDENTITY_FILES)
fatal("%.200s line %d: Too many identity files specified (max %d).",
filename, linenum, SSH_MAX_IDENTITY_FILES);
options->identity_files[options->num_identity_files++] = xstrdup(cp);
charptr = (opcode == oIdentityFile) ?
&options->identity_files[*intptr] :
&options->identity_files2[*intptr];
*charptr = xstrdup(cp);
*intptr = *intptr + 1;
}
break;
@ -393,6 +414,14 @@ process_config_line(Options *options, const char *host,
charptr = &options->user_hostfile;
goto parse_string;
case oGlobalKnownHostsFile2:
charptr = &options->system_hostfile2;
goto parse_string;
case oUserKnownHostsFile2:
charptr = &options->user_hostfile2;
goto parse_string;
case oHostName:
charptr = &options->hostname;
goto parse_string;
@ -443,6 +472,26 @@ process_config_line(Options *options, const char *host,
*intptr = value;
break;
case oCiphers:
cp = strtok(NULL, WHITESPACE);
if (!ciphers_valid(cp))
fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
filename, linenum, cp ? cp : "<NONE>");
if (*activep && options->ciphers == NULL)
options->ciphers = xstrdup(cp);
break;
case oProtocol:
intptr = &options->protocol;
cp = strtok(NULL, WHITESPACE);
value = proto_spec(cp);
if (value == SSH_PROTO_UNKNOWN)
fatal("%.200s line %d: Bad protocol spec '%s'.",
filename, linenum, cp ? cp : "<NONE>");
if (*activep && *intptr == SSH_PROTO_UNKNOWN)
*intptr = value;
break;
case oLogLevel:
intptr = (int *) &options->log_level;
cp = strtok(NULL, WHITESPACE);
@ -543,7 +592,7 @@ process_config_line(Options *options, const char *host,
* there is an error. If the file does not exist, this returns immediately.
*/
void
void
read_config_file(const char *filename, const char *host, Options *options)
{
FILE *f;
@ -583,7 +632,7 @@ read_config_file(const char *filename, const char *host, Options *options)
* system config file. Last, fill_default_options is called.
*/
void
void
initialize_options(Options * options)
{
memset(options, 'X', sizeof(*options));
@ -593,6 +642,7 @@ initialize_options(Options * options)
options->use_privileged_port = -1;
options->rhosts_authentication = -1;
options->rsa_authentication = -1;
options->dsa_authentication = -1;
options->skey_authentication = -1;
#ifdef KRB4
options->kerberos_authentication = -1;
@ -615,13 +665,18 @@ initialize_options(Options * options)
options->connection_attempts = -1;
options->number_of_password_prompts = -1;
options->cipher = -1;
options->ciphers = NULL;
options->protocol = SSH_PROTO_UNKNOWN;
options->num_identity_files = 0;
options->num_identity_files2 = 0;
options->hostname = NULL;
options->proxy_command = NULL;
options->user = NULL;
options->escape_char = -1;
options->system_hostfile = NULL;
options->user_hostfile = NULL;
options->system_hostfile2 = NULL;
options->user_hostfile2 = NULL;
options->num_local_forwards = 0;
options->num_remote_forwards = 0;
options->log_level = (LogLevel) - 1;
@ -632,7 +687,7 @@ initialize_options(Options * options)
* options for which no value has been specified with their default values.
*/
void
void
fill_default_options(Options * options)
{
if (options->forward_agent == -1)
@ -647,6 +702,8 @@ fill_default_options(Options * options)
options->rhosts_authentication = 1;
if (options->rsa_authentication == -1)
options->rsa_authentication = 1;
if (options->dsa_authentication == -1)
options->dsa_authentication = 1;
if (options->skey_authentication == -1)
options->skey_authentication = 0;
#ifdef KRB4
@ -688,18 +745,31 @@ fill_default_options(Options * options)
/* Selected in ssh_login(). */
if (options->cipher == -1)
options->cipher = SSH_CIPHER_NOT_SET;
/* options->ciphers, default set in myproposals.h */
if (options->protocol == SSH_PROTO_UNKNOWN)
options->protocol = SSH_PROTO_1|SSH_PROTO_2|SSH_PROTO_1_PREFERRED;
if (options->num_identity_files == 0) {
options->identity_files[0] =
xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
options->num_identity_files = 1;
}
if (options->num_identity_files2 == 0) {
options->identity_files2[0] =
xmalloc(2 + strlen(SSH_CLIENT_ID_DSA) + 1);
sprintf(options->identity_files2[0], "~/%.100s", SSH_CLIENT_ID_DSA);
options->num_identity_files2 = 1;
}
if (options->escape_char == -1)
options->escape_char = '~';
if (options->system_hostfile == NULL)
options->system_hostfile = SSH_SYSTEM_HOSTFILE;
if (options->user_hostfile == NULL)
options->user_hostfile = SSH_USER_HOSTFILE;
if (options->system_hostfile2 == NULL)
options->system_hostfile2 = SSH_SYSTEM_HOSTFILE2;
if (options->user_hostfile2 == NULL)
options->user_hostfile2 = SSH_USER_HOSTFILE2;
if (options->log_level == (LogLevel) - 1)
options->log_level = SYSLOG_LEVEL_INFO;
/* options->proxy_command should not be set by default */

View File

@ -1,19 +1,19 @@
/*
*
*
* readconf.h
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Sat Apr 22 00:25:29 1995 ylo
*
*
* Functions for reading the configuration file.
*
*
*/
/* RCSID("$Id: readconf.h,v 1.13 1999/12/01 13:59:15 markus Exp $"); */
/* RCSID("$Id: readconf.h,v 1.18 2000/05/08 17:12:15 markus Exp $"); */
#ifndef READCONF_H
#define READCONF_H
@ -36,6 +36,7 @@ typedef struct {
int rhosts_rsa_authentication; /* Try rhosts with RSA
* authentication. */
int rsa_authentication; /* Try RSA authentication. */
int dsa_authentication; /* Try DSA authentication. */
int skey_authentication; /* Try S/Key or TIS authentication. */
#ifdef KRB4
int kerberos_authentication; /* Try Kerberos
@ -64,6 +65,8 @@ typedef struct {
int number_of_password_prompts; /* Max number of password
* prompts. */
int cipher; /* Cipher to use. */
char *ciphers; /* SSH2 ciphers in order of preference. */
int protocol; /* Protocol in order of preference. */
char *hostname; /* Real host to connect. */
char *proxy_command; /* Proxy command for connecting the host. */
char *user; /* User to log in as. */
@ -71,9 +74,13 @@ typedef struct {
char *system_hostfile;/* Path for /etc/ssh_known_hosts. */
char *user_hostfile; /* Path for $HOME/.ssh/known_hosts. */
char *system_hostfile2;
char *user_hostfile2;
int num_identity_files; /* Number of files for RSA identities. */
int num_identity_files2; /* DSA identities. */
char *identity_files[SSH_MAX_IDENTITY_FILES];
char *identity_files2[SSH_MAX_IDENTITY_FILES];
/* Local TCP/IP forward requests. */
int num_local_forwards;
@ -104,7 +111,7 @@ void fill_default_options(Options * options);
* only sets those values that have not already been set. Returns 0 for legal
* options
*/
int
int
process_config_line(Options * options, const char *host,
char *line, const char *filename, int linenum,
int *activep);
@ -114,7 +121,7 @@ process_config_line(Options * options, const char *host,
* should already be initialized before this call. This never returns if
* there is an error. If the file does not exist, this returns immediately.
*/
void
void
read_config_file(const char *filename, const char *host,
Options * options);
@ -122,7 +129,7 @@ read_config_file(const char *filename, const char *host,
* Adds a local TCP/IP port forward to options. Never returns if there is an
* error.
*/
void
void
add_local_forward(Options * options, u_short port, const char *host,
u_short host_port);
@ -130,7 +137,7 @@ add_local_forward(Options * options, u_short port, const char *host,
* Adds a remote TCP/IP port forward to options. Never returns if there is
* an error.
*/
void
void
add_remote_forward(Options * options, u_short port, const char *host,
u_short host_port);

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

@ -1,41 +1,41 @@
/*
*
*
* rsa.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 3 22:07:06 1995 ylo
*
*
* Description of the RSA algorithm can be found e.g. from the following sources:
*
*
* Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1994.
*
*
* Jennifer Seberry and Josed Pieprzyk: Cryptography: An Introduction to
* Computer Security. Prentice-Hall, 1989.
*
*
* Man Young Rhee: Cryptography and Secure Data Communications. McGraw-Hill,
* 1994.
*
*
* R. Rivest, A. Shamir, and L. M. Adleman: Cryptographic Communications
* System and Method. US Patent 4,405,829, 1983.
*
*
* Hans Riesel: Prime Numbers and Computer Methods for Factorization.
* Birkhauser, 1994.
*
*
* The RSA Frequently Asked Questions document by RSA Data Security, Inc., 1995.
*
*
* RSA in 3 lines of perl by Adam Back <aba@atlax.ex.ac.uk>, 1995, as included
* below:
*
*
* [gone - had to be deleted - what a pity]
*
*
*/
#include "includes.h"
RCSID("$Id: rsa.c,v 1.13 2000/03/16 20:56:14 markus Exp $");
RCSID("$Id: rsa.c,v 1.14 2000/04/14 10:30:32 markus Exp $");
#include "rsa.h"
#include "ssh.h"

View File

@ -1,25 +1,25 @@
/*
*
*
* rsa.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 3 22:01:06 1995 ylo
*
*
* RSA key generation, encryption and decryption.
*
*
*/
/* RCSID("$Id: rsa.h,v 1.4 1999/11/24 19:53:50 markus Exp $"); */
/* RCSID("$Id: rsa.h,v 1.6 2000/04/14 10:30:32 markus Exp $"); */
#ifndef RSA_H
#define RSA_H
#include <ssl/bn.h>
#include <ssl/rsa.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
/* Calls SSL RSA_generate_key, only copies to prv and pub */
void rsa_generate_key(RSA * prv, RSA * pub, unsigned int bits);

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

@ -1,29 +1,30 @@
/*
*
*
* servconf.c
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Mon Aug 21 15:48:58 1995 ylo
*
*
*/
#include "includes.h"
RCSID("$Id: servconf.c,v 1.31 2000/03/07 20:40:41 markus Exp $");
RCSID("$Id: servconf.c,v 1.40 2000/05/08 17:12:15 markus Exp $");
#include "ssh.h"
#include "servconf.h"
#include "xmalloc.h"
#include "compat.h"
/* add listen address */
void add_listen_addr(ServerOptions *options, char *addr);
/* Initializes the server options to their default values. */
void
void
initialize_server_options(ServerOptions *options)
{
memset(options, 0, sizeof(*options));
@ -31,6 +32,8 @@ initialize_server_options(ServerOptions *options)
options->ports_from_cmdline = 0;
options->listen_addrs = NULL;
options->host_key_file = NULL;
options->host_dsa_key_file = NULL;
options->pid_file = NULL;
options->server_key_bits = -1;
options->login_grace_time = -1;
options->key_regeneration_time = -1;
@ -48,6 +51,7 @@ initialize_server_options(ServerOptions *options)
options->rhosts_authentication = -1;
options->rhosts_rsa_authentication = -1;
options->rsa_authentication = -1;
options->dsa_authentication = -1;
#ifdef KRB4
options->kerberos_authentication = -1;
options->kerberos_or_local_passwd = -1;
@ -67,9 +71,12 @@ initialize_server_options(ServerOptions *options)
options->num_deny_users = 0;
options->num_allow_groups = 0;
options->num_deny_groups = 0;
options->ciphers = NULL;
options->protocol = SSH_PROTO_UNKNOWN;
options->gateway_ports = -1;
}
void
void
fill_default_server_options(ServerOptions *options)
{
if (options->num_ports == 0)
@ -78,6 +85,10 @@ fill_default_server_options(ServerOptions *options)
add_listen_addr(options, NULL);
if (options->host_key_file == NULL)
options->host_key_file = HOST_KEY_FILE;
if (options->host_dsa_key_file == NULL)
options->host_dsa_key_file = HOST_DSA_KEY_FILE;
if (options->pid_file == NULL)
options->pid_file = SSH_DAEMON_PID_FILE;
if (options->server_key_bits == -1)
options->server_key_bits = 768;
if (options->login_grace_time == -1)
@ -112,6 +123,8 @@ fill_default_server_options(ServerOptions *options)
options->rhosts_rsa_authentication = 0;
if (options->rsa_authentication == -1)
options->rsa_authentication = 1;
if (options->dsa_authentication == -1)
options->dsa_authentication = 1;
#ifdef KRB4
if (options->kerberos_authentication == -1)
options->kerberos_authentication = (access(KEYFILE, R_OK) == 0);
@ -136,6 +149,10 @@ fill_default_server_options(ServerOptions *options)
options->permit_empty_passwd = 0;
if (options->use_login == -1)
options->use_login = 0;
if (options->protocol == SSH_PROTO_UNKNOWN)
options->protocol = SSH_PROTO_1|SSH_PROTO_2;
if (options->gateway_ports == -1)
options->gateway_ports = 0;
}
#define WHITESPACE " \t\r\n"
@ -159,7 +176,8 @@ typedef enum {
sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset,
sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
sIgnoreUserKnownHosts
sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile,
sGatewayPorts, sDSAAuthentication
} ServerOpCodes;
/* Textual representation of the tokens. */
@ -169,6 +187,8 @@ static struct {
} keywords[] = {
{ "port", sPort },
{ "hostkey", sHostKeyFile },
{ "hostdsakey", sHostDSAKeyFile },
{ "pidfile", sPidFile },
{ "serverkeybits", sServerKeyBits },
{ "logingracetime", sLoginGraceTime },
{ "keyregenerationinterval", sKeyRegenerationTime },
@ -178,6 +198,7 @@ static struct {
{ "rhostsauthentication", sRhostsAuthentication },
{ "rhostsrsaauthentication", sRhostsRSAAuthentication },
{ "rsaauthentication", sRSAAuthentication },
{ "dsaauthentication", sDSAAuthentication },
#ifdef KRB4
{ "kerberosauthentication", sKerberosAuthentication },
{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd },
@ -207,6 +228,9 @@ static struct {
{ "denyusers", sDenyUsers },
{ "allowgroups", sAllowGroups },
{ "denygroups", sDenyGroups },
{ "ciphers", sCiphers },
{ "protocol", sProtocol },
{ "gatewayports", sGatewayPorts },
{ NULL, 0 }
};
@ -215,7 +239,7 @@ static struct {
* returns if the token is not known.
*/
static ServerOpCodes
static ServerOpCodes
parse_token(const char *cp, const char *filename,
int linenum)
{
@ -233,7 +257,7 @@ parse_token(const char *cp, const char *filename,
/*
* add listen address
*/
void
void
add_listen_addr(ServerOptions *options, char *addr)
{
extern int IPv4or6;
@ -263,7 +287,7 @@ add_listen_addr(ServerOptions *options, char *addr)
/* Reads the server configuration file. */
void
void
read_server_config(ServerOptions *options, const char *filename)
{
FILE *f;
@ -299,7 +323,7 @@ read_server_config(ServerOptions *options, const char *filename)
"ListenAdress.\n", filename, linenum);
if (options->num_ports >= MAX_PORTS)
fatal("%s line %d: too many ports.\n",
filename, linenum);
filename, linenum);
cp = strtok(NULL, WHITESPACE);
if (!cp)
fatal("%s line %d: missing port number.\n",
@ -338,11 +362,25 @@ read_server_config(ServerOptions *options, const char *filename)
break;
case sHostKeyFile:
charptr = &options->host_key_file;
case sHostDSAKeyFile:
charptr = (opcode == sHostKeyFile ) ?
&options->host_key_file : &options->host_dsa_key_file;
cp = strtok(NULL, WHITESPACE);
if (!cp) {
fprintf(stderr, "%s line %d: missing file name.\n",
filename, linenum);
filename, linenum);
exit(1);
}
if (*charptr == NULL)
*charptr = tilde_expand_filename(cp, getuid());
break;
case sPidFile:
charptr = &options->pid_file;
cp = strtok(NULL, WHITESPACE);
if (!cp) {
fprintf(stderr, "%s line %d: missing file name.\n",
filename, linenum);
exit(1);
}
if (*charptr == NULL)
@ -416,6 +454,10 @@ read_server_config(ServerOptions *options, const char *filename)
intptr = &options->rsa_authentication;
goto parse_flag;
case sDSAAuthentication:
intptr = &options->dsa_authentication;
goto parse_flag;
#ifdef KRB4
case sKerberosAuthentication:
intptr = &options->kerberos_authentication;
@ -482,13 +524,17 @@ read_server_config(ServerOptions *options, const char *filename)
intptr = &options->use_login;
goto parse_flag;
case sGatewayPorts:
intptr = &options->gateway_ports;
goto parse_flag;
case sLogFacility:
intptr = (int *) &options->log_facility;
cp = strtok(NULL, WHITESPACE);
value = log_facility_number(cp);
if (value == (SyslogFacility) - 1)
fatal("%.200s line %d: unsupported log facility '%s'\n",
filename, linenum, cp ? cp : "<NONE>");
filename, linenum, cp ? cp : "<NONE>");
if (*intptr == -1)
*intptr = (SyslogFacility) value;
break;
@ -499,55 +545,67 @@ read_server_config(ServerOptions *options, const char *filename)
value = log_level_number(cp);
if (value == (LogLevel) - 1)
fatal("%.200s line %d: unsupported log level '%s'\n",
filename, linenum, cp ? cp : "<NONE>");
filename, linenum, cp ? cp : "<NONE>");
if (*intptr == -1)
*intptr = (LogLevel) value;
break;
case sAllowUsers:
while ((cp = strtok(NULL, WHITESPACE))) {
if (options->num_allow_users >= MAX_ALLOW_USERS) {
fprintf(stderr, "%s line %d: too many allow users.\n",
filename, linenum);
exit(1);
}
if (options->num_allow_users >= MAX_ALLOW_USERS)
fatal("%s line %d: too many allow users.\n",
filename, linenum);
options->allow_users[options->num_allow_users++] = xstrdup(cp);
}
break;
case sDenyUsers:
while ((cp = strtok(NULL, WHITESPACE))) {
if (options->num_deny_users >= MAX_DENY_USERS) {
fprintf(stderr, "%s line %d: too many deny users.\n",
filename, linenum);
exit(1);
}
if (options->num_deny_users >= MAX_DENY_USERS)
fatal( "%s line %d: too many deny users.\n",
filename, linenum);
options->deny_users[options->num_deny_users++] = xstrdup(cp);
}
break;
case sAllowGroups:
while ((cp = strtok(NULL, WHITESPACE))) {
if (options->num_allow_groups >= MAX_ALLOW_GROUPS) {
fprintf(stderr, "%s line %d: too many allow groups.\n",
filename, linenum);
exit(1);
}
if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
fatal("%s line %d: too many allow groups.\n",
filename, linenum);
options->allow_groups[options->num_allow_groups++] = xstrdup(cp);
}
break;
case sDenyGroups:
while ((cp = strtok(NULL, WHITESPACE))) {
if (options->num_deny_groups >= MAX_DENY_GROUPS) {
fprintf(stderr, "%s line %d: too many deny groups.\n",
filename, linenum);
exit(1);
}
if (options->num_deny_groups >= MAX_DENY_GROUPS)
fatal("%s line %d: too many deny groups.\n",
filename, linenum);
options->deny_groups[options->num_deny_groups++] = xstrdup(cp);
}
break;
case sCiphers:
cp = strtok(NULL, WHITESPACE);
if (!ciphers_valid(cp))
fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
filename, linenum, cp ? cp : "<NONE>");
if (options->ciphers == NULL)
options->ciphers = xstrdup(cp);
break;
case sProtocol:
intptr = &options->protocol;
cp = strtok(NULL, WHITESPACE);
value = proto_spec(cp);
if (value == SSH_PROTO_UNKNOWN)
fatal("%s line %d: Bad protocol spec '%s'.",
filename, linenum, cp ? cp : "<NONE>");
if (*intptr == SSH_PROTO_UNKNOWN)
*intptr = value;
break;
default:
fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n",
filename, linenum, cp, opcode);

View File

@ -1,19 +1,19 @@
/*
*
*
* servconf.h
*
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
*
*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
*
* Created: Mon Aug 21 15:35:03 1995 ylo
*
*
* Definitions for server configuration data and for the functions reading it.
*
*
*/
/* RCSID("$Id: servconf.h,v 1.15 2000/01/04 00:08:00 markus Exp $"); */
/* RCSID("$Id: servconf.h,v 1.22 2000/05/06 17:45:37 markus Exp $"); */
#ifndef SERVCONF_H
#define SERVCONF_H
@ -32,6 +32,8 @@ typedef struct {
char *listen_addr; /* Address on which the server listens. */
struct addrinfo *listen_addrs; /* Addresses on which the server listens. */
char *host_key_file; /* File containing host key. */
char *host_dsa_key_file; /* File containing dsa host key. */
char *pid_file; /* Where to put our pid */
int server_key_bits;/* Size of the server key. */
int login_grace_time; /* Disconnect if no auth in this time
* (sec). */
@ -47,6 +49,9 @@ typedef struct {
* searching at */
int strict_modes; /* If true, require string home dir modes. */
int keepalives; /* If true, set SO_KEEPALIVE. */
char *ciphers; /* Ciphers in order of preference. */
int protocol; /* Protocol in order of preference. */
int gateway_ports; /* If true, allow remote connects to forwarded ports. */
SyslogFacility log_facility; /* Facility for system logging. */
LogLevel log_level; /* Level for system logging. */
int rhosts_authentication; /* If true, permit rhosts
@ -54,6 +59,7 @@ typedef struct {
int rhosts_rsa_authentication; /* If true, permit rhosts RSA
* authentication. */
int rsa_authentication; /* If true, permit RSA authentication. */
int dsa_authentication; /* If true, permit DSA authentication. */
#ifdef KRB4
int kerberos_authentication; /* If true, permit Kerberos
* authentication. */

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

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-agent.c,v 1.26 2000/03/16 20:56:14 markus Exp $ */
/* $OpenBSD: ssh-agent.c,v 1.31 2000/04/29 18:11:52 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -9,7 +9,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: ssh-agent.c,v 1.26 2000/03/16 20:56:14 markus Exp $");
RCSID("$OpenBSD: ssh-agent.c,v 1.31 2000/04/29 18:11:52 markus Exp $");
#include "ssh.h"
#include "rsa.h"
@ -21,7 +21,7 @@ RCSID("$OpenBSD: ssh-agent.c,v 1.26 2000/03/16 20:56:14 markus Exp $");
#include "getput.h"
#include "mpaux.h"
#include <ssl/md5.h>
#include <openssl/md5.h>
typedef struct {
int fd;
@ -46,7 +46,7 @@ Identity *identities = NULL;
int max_fd = 0;
/* pid of shell == parent of agent */
int parent_pid = -1;
pid_t parent_pid = -1;
/* pathname and directory for AUTH_SOCKET */
char socket_name[1024];
@ -174,7 +174,7 @@ process_remove_identity(SocketEntry *e)
buffer_get_bignum(&e->input, n);
if (bits != BN_num_bits(n))
error("Warning: identity keysize mismatch: actual %d, announced %d",
log("Warning: identity keysize mismatch: actual %d, announced %d",
BN_num_bits(n), bits);
/* Check if we have the key. */
@ -403,7 +403,7 @@ prepare_select(fd_set *readset, fd_set *writeset)
}
}
void
void
after_select(fd_set *readset, fd_set *writeset)
{
unsigned int i;
@ -436,6 +436,8 @@ after_select(fd_set *readset, fd_set *writeset)
shutdown(sockets[i].fd, SHUT_RDWR);
close(sockets[i].fd);
sockets[i].type = AUTH_UNUSED;
buffer_free(&sockets[i].input);
buffer_free(&sockets[i].output);
break;
}
buffer_consume(&sockets[i].output, len);
@ -446,6 +448,8 @@ after_select(fd_set *readset, fd_set *writeset)
shutdown(sockets[i].fd, SHUT_RDWR);
close(sockets[i].fd);
sockets[i].type = AUTH_UNUSED;
buffer_free(&sockets[i].input);
buffer_free(&sockets[i].output);
break;
}
buffer_append(&sockets[i].input, buf, len);
@ -460,7 +464,7 @@ after_select(fd_set *readset, fd_set *writeset)
void
check_parent_exists(int sig)
{
if (kill(parent_pid, 0) < 0) {
if (parent_pid != -1 && kill(parent_pid, 0) < 0) {
/* printf("Parent has died - Authentication agent exiting.\n"); */
exit(1);
}
@ -546,6 +550,7 @@ main(int ac, char **av)
}
pid = atoi(pidstr);
if (pid < 1) { /* XXX PID_MAX check too */
/* Yes, PID_MAX check please */
fprintf(stderr, "%s=\"%s\", which is not a good PID\n",
SSH_AGENTPID_ENV_NAME, pidstr);
exit(1);
@ -637,8 +642,8 @@ main(int ac, char **av)
}
signal(SIGINT, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, cleanup_exit);
signal(SIGTERM, cleanup_exit);
signal(SIGHUP, cleanup_exit);
signal(SIGTERM, cleanup_exit);
while (1) {
FD_ZERO(&readset);
FD_ZERO(&writeset);

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

@ -9,7 +9,7 @@
.\"
.\" Created: Sat Apr 22 21:55:14 1995 ylo
.\"
.\" $Id: ssh.1,v 1.43 2000/03/24 03:04:46 brad Exp $
.\" $Id: ssh.1,v 1.52 2000/05/08 17:21:32 hugh Exp $
.\"
.Dd September 25, 1999
.Dt SSH 1
@ -24,8 +24,8 @@
.Op Ar command
.Pp
.Nm ssh
.Op Fl afgknqtvxCPX46
.Op Fl c Ar blowfish | 3des
.Op Fl afgknqtvxCPX246
.Op Fl c Ar cipher_spec
.Op Fl e Ar escape_char
.Op Fl i Ar identity_file
.Op Fl l Ar login_name
@ -49,7 +49,7 @@
.Oc
.Op Ar hostname | user@hostname
.Op Ar command
.Sh DESCRIPTION
.Sh DESCRIPTION
.Nm
(Secure Shell) is a program for logging into a remote machine and for
executing commands on a remote machine.
@ -60,10 +60,13 @@ X11 connections and
arbitrary TCP/IP ports can also be forwarded over the secure channel.
.Pp
.Nm
connects and logs into the specified
connects and logs into the specified
.Ar hostname .
The user must prove
his/her identity to the remote machine using one of several methods.
his/her identity to the remote machine using one of several methods
depending on the protocol version used:
.Pp
.Ss SSH protocol version 1
.Pp
First, if the machine the user logs in from is listed in
.Pa /etc/hosts.equiv
@ -71,7 +74,7 @@ or
.Pa /etc/shosts.equiv
on the remote machine, and the user names are
the same on both sides, the user is immediately permitted to log in.
Second, if
Second, if
.Pa \&.rhosts
or
.Pa \&.shosts
@ -88,13 +91,13 @@ or
.Pa hosts.equiv
method combined with RSA-based host authentication.
It means that if the login would be permitted by
.Pa \&.rhosts ,
.Pa \&.shosts ,
.Pa $HOME/.rhosts ,
.Pa $HOME/.shosts ,
.Pa /etc/hosts.equiv ,
or
.Pa /etc/shosts.equiv ,
and if additionally the server can verify the client's
host key (see
host key (see
.Pa /etc/ssh_known_hosts
and
.Pa $HOME/.ssh/known_hosts
@ -105,21 +108,21 @@ This authentication method closes security holes due to IP
spoofing, DNS spoofing and routing spoofing.
[Note to the administrator:
.Pa /etc/hosts.equiv ,
.Pa \&.rhosts ,
.Pa $HOME/.rhosts ,
and the rlogin/rsh protocol in general, are inherently insecure and should be
disabled if security is desired.]
.Pp
As a third authentication method,
As a third authentication method,
.Nm
supports RSA based authentication.
The scheme is based on public-key cryptography: there are cryptosystems
where encryption and decryption are done using separate keys, and it
is not possible to derive the decryption key from the encryption key.
RSA is one such system.
The idea is that each user creates a public/private
The idea is that each user creates a public/private
key pair for authentication purposes.
The server knows the public key, and only the user knows the private key.
The file
The file
.Pa $HOME/.ssh/authorized_keys
lists the public keys that are permitted for logging
in.
@ -142,19 +145,19 @@ key but without disclosing it to the server.
implements the RSA authentication protocol automatically.
The user creates his/her RSA key pair by running
.Xr ssh-keygen 1 .
This stores the private key in
.Pa \&.ssh/identity
This stores the private key in
.Pa $HOME/.ssh/identity
and the public key in
.Pa \&.ssh/identity.pub
.Pa $HOME/.ssh/identity.pub
in the user's home directory.
The user should then copy the
.Pa identity.pub
to
.Pa \&.ssh/authorized_keys
in his/her home directory on the remote machine (the
to
.Pa $HOME/.ssh/authorized_keys
in his/her home directory on the remote machine (the
.Pa authorized_keys
file corresponds to the conventional
.Pa \&.rhosts
file corresponds to the conventional
.Pa $HOME/.rhosts
file, and has one key
per line, though the lines can be very long).
After this, the user can log in without giving the password.
@ -167,13 +170,45 @@ See
.Xr ssh-agent 1
for more information.
.Pp
If other authentication methods fail,
If other authentication methods fail,
.Nm
prompts the user for a password.
The password is sent to the remote
host for checking; however, since all communications are encrypted,
the password cannot be seen by someone listening on the network.
.Pp
.Ss SSH protocol version 2
.Pp
When a user connects using the protocol version 2
different authentication methods are available:
At first, the client attempts to authenticate using the public key method.
If this method fails password authentication is tried.
.Pp
The public key method is similar to RSA authentication described
in the previous section except that the DSA algorithm is used
instead of the patented RSA algorithm.
The client uses his private DSA key
.Pa $HOME/.ssh/id_dsa
to sign the session identifier and sends the result to the server.
The server checks whether the matching public key is listed in
.Pa $HOME/.ssh/authorized_keys2
and grants access if both the key is found and the signature is correct.
The session identifier is derived from a shared Diffie-Hellman value
and is only known to the client and the server.
.Pp
If public key authentication fails or is not available a password
can be sent encrypted to the remote host for proving the user's identity.
This protocol 2 implementation does not yet support Kerberos or
S/Key authentication.
.Pp
Protocol 2 provides additional mechanisms for confidentiality
(the traffic is encrypted using 3DES, Blowfish, CAST128 or Arcfour)
and integrity (hmac-sha1, hmac-md5).
Note that protocol 1 lacks a strong mechanism for ensuring the
integrity of the connection.
.Pp
.Ss Login session and remote execution
.Pp
When the user's identity has been accepted by the server, the server
either executes the given command, or logs into the machine and gives
the user a normal shell on the remote machine.
@ -188,7 +223,7 @@ and suspend
with
.Ic ~^Z .
All forwarded connections can be listed with
.Ic ~#
.Ic ~#
and if
the session blocks waiting for forwarded X11 or TCP/IP
connections to terminate, it can be backgrounded with
@ -219,6 +254,8 @@ The exit status of the remote program is returned as the exit status
of
.Nm ssh .
.Pp
.Ss X11 and TCP forwarding
.Pp
If the user is using X11 (the
.Ev DISPLAY
environment variable is set), the connection to the X11 display is
@ -232,7 +269,7 @@ Forwarding of X11 connections can be
configured on the command line or in configuration files.
.Pp
The
.Ev DISPLAY
.Ev DISPLAY
value set by
.Nm
will point to the server machine, but with a display number greater
@ -262,15 +299,22 @@ be specified either on command line or in a configuration file.
One possible application of TCP/IP forwarding is a secure connection to an
electronic purse; another is going trough firewalls.
.Pp
.Ss Server authentication
.Pp
.Nm
automatically maintains and checks a database containing RSA-based
automatically maintains and checks a database containing
identifications for all hosts it has ever been used with.
The database is stored in
.Pa \&.ssh/known_hosts
RSA host keys are stored in
.Pa $HOME/.ssh/known_hosts
and
DSA host keys are stored in
.Pa $HOME/.ssh/known_hosts2
in the user's home directory.
Additionally, the file
Additionally, the files
.Pa /etc/ssh_known_hosts
is automatically checked for known hosts.
and
.Pa /etc/ssh_known_hosts2
are automatically checked for known hosts.
Any new hosts are automatically added to the user's file.
If a host's identification
ever changes,
@ -290,18 +334,23 @@ host key is not known or has changed.
Disables forwarding of the authentication agent connection.
This may also be specified on a per-host basis in the configuration file.
.It Fl c Ar blowfish|3des
Selects the cipher to use for encrypting the session.
Selects the cipher to use for encrypting the session.
.Ar 3des
is used by default.
It is believed to be secure.
It is believed to be secure.
.Ar 3des
(triple-des) is an encrypt-decrypt-encrypt triple with three different keys.
It is presumably more secure than the
.Ar des
cipher which is no longer supported in ssh.
cipher which is no longer supported in
.Nm ssh .
.Ar blowfish
is a fast block cipher, it appears very secure and is much faster than
.Ar 3des .
.It Fl c Ar "3des-cbc,blowfish-cbc,arcfour,cast128-cbc"
Additionally, for protocol version 2 a comma-separated list of ciphers can
be specified in order of preference. Protocol version 2 supports
3DES, Blowfish and CAST128 in CBC mode and Arcfour.
.It Fl e Ar ch|^ch|none
Sets the escape character for sessions with a pty (default:
.Ql ~ ) .
@ -322,7 +371,7 @@ This is useful if
.Nm
is going to ask for passwords or passphrases, but the user
wants it in the background.
This implies
This implies
.Fl n .
The recommended way to start X11 programs at a remote site is with
something like
@ -330,10 +379,10 @@ something like
.It Fl g
Allows remote hosts to connect to local forwarded ports.
.It Fl i Ar identity_file
Selects the file from which the identity (private key) for
Selects the file from which the identity (private key) for
RSA authentication is read.
Default is
.Pa \&.ssh/identity
Default is
.Pa $HOME/.ssh/identity
in the user's home directory.
Identity files may also be specified on
a per-host basis in the configuration file.
@ -455,6 +504,10 @@ from the local machine.
Port forwardings can also be specified in the configuration file.
Privileged ports can be forwarded only when
logging in as root on the remote machine.
.It Fl 2
Forces
.Nm
to try protocol version 2 only.
.It Fl 4
Forces
.Nm
@ -548,6 +601,12 @@ and
are supported.
The default is
.Dq 3des .
.It Cm Ciphers
Specifies the ciphers allowed for protocol version 2
in order of preference.
Multiple ciphers must be comma-separated.
The default is
.Dq 3des-cbc,blowfish-cbc,arcfour,cast128-cbc .
.It Cm Compression
Specifies whether to use compression.
The argument must be
@ -565,6 +624,15 @@ Specifies the number of tries (one per second) to make before falling
back to rsh or exiting.
The argument must be an integer.
This may be useful in scripts if the connection sometimes fails.
.It Cm DSAAuthentication
Specifies whether to try DSA authentication.
The argument to this keyword must be
.Dq yes
or
.Dq no .
DSA authentication will only be
attempted if a DSA identity file exists.
Note that this option applies to protocol version 2 only.
.It Cm EscapeChar
Sets the escape character (default:
.Ql ~ ) .
@ -577,12 +645,12 @@ followed by a letter, or
to disable the escape
character entirely (making the connection transparent for binary
data).
.It Cm FallBackToRsh
.It Cm FallBackToRsh
Specifies that if connecting via
.Nm
fails due to a connection refused error (there is no
.Xr sshd 8
listening on the remote host),
listening on the remote host),
.Xr rsh 1
should automatically be used instead (after a suitable warning about
the session being unencrypted).
@ -599,10 +667,10 @@ or
.Dq no .
.It Cm ForwardX11
Specifies whether X11 connections will be automatically redirected
over the secure channel and
over the secure channel and
.Ev DISPLAY
set.
The argument must be
The argument must be
.Dq yes
or
.Dq no .
@ -618,7 +686,7 @@ or
The default is
.Dq no .
.It Cm GlobalKnownHostsFile
Specifies a file to use instead of
Specifies a file to use instead of
.Pa /etc/ssh_known_hosts .
.It Cm HostName
Specifies the real host name to log into.
@ -630,7 +698,7 @@ specifications).
.It Cm IdentityFile
Specifies the file from which the user's RSA authentication identity
is read (default
.Pa .ssh/identity
.Pa $HOME/.ssh/identity
in the user's home directory).
Additionally, any identities represented by the authentication agent
will be used for authentication.
@ -639,6 +707,16 @@ syntax to refer to a user's home directory.
It is possible to have
multiple identity files specified in configuration files; all these
identities will be tried in sequence.
.It Cm IdentityFile2
Specifies the file from which the user's DSA authentication identity
is read (default
.Pa $HOME/.ssh/id_dsa
in the user's home directory).
The file name may use the tilde
syntax to refer to a user's home directory.
It is possible to have
multiple identity files specified in configuration files; all these
identities will be tried in sequence.
.It Cm KeepAlive
Specifies whether the system should send keepalive messages to the
other side.
@ -694,9 +772,25 @@ The argument to this keyword must be
.Dq yes
or
.Dq no .
Note that this option applies to both protocol version 1 and 2.
.It Cm Port
Specifies the port number to connect on the remote host.
Default is 22.
.It Cm Protocol
Specifies the protocol versions
.Nm
should support in order of preference.
The possible values are
.Dq 1
and
.Dq 2 .
Multiple versions must be comma-separated.
The default is
.Dq 1,2 .
This means that
.Nm
tries version 1 and falls back to version 2
if version 1 is not available.
.It Cm ProxyCommand
Specifies the command to use to connect to the server.
The command
@ -761,6 +855,7 @@ or
RSA authentication will only be
attempted if the identity file exists, or an authentication agent is
running.
Note that this option applies to protocol version 1 only.
.It Cm SkeyAuthentication
Specifies whether to use
.Xr skey 1
@ -773,14 +868,18 @@ The default is
.Dq no .
.It Cm StrictHostKeyChecking
If this flag is set to
.Dq yes ,
.Dq yes ,
.Nm
ssh will never automatically add host keys to the
.Pa $HOME/.ssh/known_hosts
file, and refuses to connect hosts whose host key has changed.
and
.Pa $HOME/.ssh/known_hosts2
files, and refuses to connect hosts whose host key has changed.
This provides maximum protection against trojan horse attacks.
However, it can be somewhat annoying if you don't have good
.Pa /etc/ssh_known_hosts
and
.Pa /etc/ssh_known_hosts2
files installed and frequently
connect new hosts.
Basically this option forces the user to manually
@ -839,7 +938,7 @@ will normally set the following environment variables:
The
.Ev DISPLAY
variable indicates the location of the X11 server.
It is automatically set by
It is automatically set by
.Nm
to point to a value of the form
.Dq hostname:n
@ -885,10 +984,10 @@ on to new connections).
Set to the name of the user logging in.
.El
.Pp
Additionally,
Additionally,
.Nm
reads
.Pa $HOME/.ssh/environment ,
reads
.Pa $HOME/.ssh/environment ,
and adds lines of the format
.Dq VARNAME=value
to the environment.
@ -900,28 +999,36 @@ in
.Pa /etc/ssh_known_hosts ) .
See
.Xr sshd 8 .
.It Pa $HOME/.ssh/identity
Contains the RSA authentication identity of the user.
This file
contains sensitive data and should be readable by the user but not
.It Pa $HOME/.ssh/identity, $HOME/.ssh/id_dsa
Contains the RSA and the DSA authentication identity of the user.
These files
contain sensitive data and should be readable by the user but not
accessible by others (read/write/execute).
Note that
.Nm
ignores this file if it is accessible by others.
ignores a private key file if it is accessible by others.
It is possible to specify a passphrase when
generating the key; the passphrase will be used to encrypt the
sensitive part of this file using 3DES.
.It Pa $HOME/.ssh/identity.pub
.It Pa $HOME/.ssh/identity.pub, $HOME/.ssh/id_dsa.pub
Contains the public key for authentication (public part of the
identity file in human-readable form).
The contents of this file should be added to
The contents of the
.Pa $HOME/.ssh/identity.pub
file should be added to
.Pa $HOME/.ssh/authorized_keys
on all machines
where you wish to log in using RSA authentication.
This file is not
The contents of the
.Pa $HOME/.ssh/id_dsa.pub
file should be added to
.Pa $HOME/.ssh/authorized_keys2
on all machines
where you wish to log in using DSA authentication.
These files are not
sensitive and can (but need not) be readable by anyone.
This file is
never used automatically and is not necessary; it is only provided for
These files are
never used automatically and are not necessary; they is only provided for
the convenience of the user.
.It Pa $HOME/.ssh/config
This is the per-user configuration file.
@ -943,9 +1050,17 @@ modulus, public exponent, modulus, and comment fields, separated by
spaces).
This file is not highly sensitive, but the recommended
permissions are read/write for the user, and not accessible by others.
.It Pa /etc/ssh_known_hosts
.It Pa $HOME/.ssh/authorized_keys2
Lists the DSA keys that can be used for logging in as this user.
This file is not highly sensitive, but the recommended
permissions are read/write for the user, and not accessible by others.
.It Pa /etc/ssh_known_hosts, /etc/ssh_known_hosts2
Systemwide list of known host keys.
This file should be prepared by the
.Pa /etc/ssh_known_hosts
contains RSA and
.Pa /etc/ssh_known_hosts2
contains DSA keys.
These files should be prepared by the
system administrator to contain the public host keys of all machines in the
organization.
This file should be world-readable.
@ -1004,7 +1119,7 @@ you can store it in
.Pa $HOME/.ssh/known_hosts .
The easiest way to do this is to
connect back to the client from the server machine using ssh; this
will automatically add the host key inxi
will automatically add the host key to
.Pa $HOME/.ssh/known_hosts .
.It Pa $HOME/.shosts
This file is used exactly the same way as
@ -1031,7 +1146,7 @@ Additionally, successful RSA host authentication is normally
required.
This file should only be writable by root.
.It Pa /etc/shosts.equiv
This file is processed exactly as
This file is processed exactly as
.Pa /etc/hosts.equiv .
This file may be useful to permit logins using
.Nm
@ -1048,7 +1163,7 @@ Commands in this file are executed by
.Nm
when the user logs in just before the user's shell (or command) is
started.
See the
See the
.Xr sshd 8
manual page for more information.
.It Pa $HOME/.ssh/environment
@ -1065,6 +1180,7 @@ but with bugs removed and newer features re-added.
Rapidly after the
1.2.12 release, newer versions of the original ssh bore successively
more restrictive licenses, and thus demand for a free version was born.
.Pp
This version of OpenSSH
.Bl -bullet
.It
@ -1074,10 +1190,10 @@ directly removed from the source code; any licensed or patented components
are chosen from
external libraries.
.It
has been updated to support ssh protocol 1.5, making it compatible with
all other ssh protocol 1 clients and servers.
has been updated to support SSH protocol 1.5 and 2, making it compatible with
all other SSH clients and servers.
.It
contains added support for
contains added support for
.Xr kerberos 8
authentication and ticket passing.
.It
@ -1091,6 +1207,8 @@ are required for proper operation.
.Pp
OpenSSH has been created by Aaron Campbell, Bob Beck, Markus Friedl,
Niels Provos, Theo de Raadt, and Dug Song.
.Pp
The support for SSH protocol 2 was written by Markus Friedl.
.Sh SEE ALSO
.Xr rlogin 1 ,
.Xr rsh 1 ,

View File

@ -11,7 +11,11 @@
*/
#include "includes.h"
RCSID("$Id: ssh.c,v 1.43 2000/03/23 21:52:02 markus Exp $");
RCSID("$Id: ssh.c,v 1.51 2000/05/08 17:12:15 markus Exp $");
#include <openssl/evp.h>
#include <openssl/dsa.h>
#include <openssl/rsa.h>
#include "xmalloc.h"
#include "ssh.h"
@ -21,6 +25,14 @@ RCSID("$Id: ssh.c,v 1.43 2000/03/23 21:52:02 markus Exp $");
#include "readconf.h"
#include "uidswap.h"
#include "ssh2.h"
#include "compat.h"
#include "channels.h"
#include "key.h"
#include "authfile.h"
extern char *__progname;
/* Flag indicating whether IPv4 or IPv6. This can be set on the command line.
Default value is AF_UNSPEC means both IPv4 and IPv6. */
int IPv4or6 = AF_UNSPEC;
@ -28,8 +40,13 @@ int IPv4or6 = AF_UNSPEC;
/* Flag indicating whether debug mode is on. This can be set on the command line. */
int debug_flag = 0;
/* Flag indicating whether a tty should be allocated */
int tty_flag = 0;
/* don't exec a shell */
int no_shell_flag = 0;
int no_tty_flag = 0;
/*
* Flag indicating that nothing should be read from stdin. This can be set
* on the command line.
@ -79,6 +96,9 @@ RSA *host_private_key = NULL;
/* Original real UID. */
uid_t original_real_uid;
/* command to be executed */
Buffer command;
/* Prints a help message to the user. This function never returns. */
void
@ -93,9 +113,9 @@ usage()
fprintf(stderr, " -k Disable Kerberos ticket and AFS token forwarding.\n");
#endif /* AFS */
fprintf(stderr, " -x Disable X11 connection forwarding.\n");
fprintf(stderr, " -X Enable X11 connection forwarding.\n");
fprintf(stderr, " -i file Identity for RSA authentication (default: ~/.ssh/identity).\n");
fprintf(stderr, " -t Tty; allocate a tty even if command is given.\n");
fprintf(stderr, " -T Do not allocate a tty.\n");
fprintf(stderr, " -v Verbose; display verbose debugging messages.\n");
fprintf(stderr, " -V Display version number only.\n");
fprintf(stderr, " -P Don't allocate a privileged port.\n");
@ -112,9 +132,11 @@ usage()
fprintf(stderr, " These cause %s to listen for connections on a port, and\n", av0);
fprintf(stderr, " forward them to the other side by connecting to host:port.\n");
fprintf(stderr, " -C Enable compression.\n");
fprintf(stderr, " -N Do not execute a shell or command.\n");
fprintf(stderr, " -g Allow remote hosts to connect to forwarded ports.\n");
fprintf(stderr, " -4 Use IPv4 only.\n");
fprintf(stderr, " -6 Use IPv6 only.\n");
fprintf(stderr, " -2 Force protocol version 2.\n");
fprintf(stderr, " -o 'option' Process the option as if it was read from a configuration file.\n");
exit(1);
}
@ -157,23 +179,22 @@ rsh_connect(char *host, char *user, Buffer * command)
exit(1);
}
int ssh_session(void);
int ssh_session2(void);
/*
* Main program for the ssh client.
*/
int
main(int ac, char **av)
{
int i, opt, optind, type, exit_status, ok, authfd;
int i, opt, optind, exit_status, ok;
u_short fwd_port, fwd_host_port;
char *optarg, *cp, buf[256];
Buffer command;
struct winsize ws;
struct stat st;
struct passwd *pw, pwcopy;
int interactive = 0, dummy;
int have_pty = 0;
int dummy;
uid_t original_effective_uid;
int plen;
/*
* Save the original real uid. It will be needed later (uid-swapping
@ -229,8 +250,8 @@ main(int ac, char **av)
if (host)
break;
if ((cp = strchr(av[optind], '@'))) {
if(cp == av[optind])
usage();
if(cp == av[optind])
usage();
options.user = av[optind];
*cp = '\0';
host = ++cp;
@ -254,39 +275,34 @@ main(int ac, char **av)
optarg = NULL;
}
switch (opt) {
case '2':
options.protocol = SSH_PROTO_2;
break;
case '4':
IPv4or6 = AF_INET;
break;
case '6':
IPv4or6 = AF_INET6;
break;
case 'n':
stdin_null_flag = 1;
break;
case 'f':
fork_after_authentication_flag = 1;
stdin_null_flag = 1;
break;
case 'x':
options.forward_x11 = 0;
break;
case 'X':
options.forward_x11 = 1;
break;
case 'g':
options.gateway_ports = 1;
break;
case 'P':
options.use_privileged_port = 0;
break;
case 'a':
options.forward_agent = 0;
break;
@ -308,26 +324,24 @@ main(int ac, char **av)
options.identity_files[options.num_identity_files++] =
xstrdup(optarg);
break;
case 't':
tty_flag = 1;
break;
case 'v':
case 'V':
fprintf(stderr, "SSH Version %s, protocol version %d.%d.\n",
SSH_VERSION, PROTOCOL_MAJOR, PROTOCOL_MINOR);
fprintf(stderr, "Compiled with SSL.\n");
fprintf(stderr, "SSH Version %s, protocol versions %d.%d/%d.%d.\n",
SSH_VERSION,
PROTOCOL_MAJOR_1, PROTOCOL_MINOR_1,
PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2);
fprintf(stderr, "Compiled with SSL (0x%8.8lx).\n", SSLeay());
if (opt == 'V')
exit(0);
debug_flag = 1;
options.log_level = SYSLOG_LEVEL_DEBUG;
break;
case 'q':
options.log_level = SYSLOG_LEVEL_QUIET;
break;
case 'e':
if (optarg[0] == '^' && optarg[2] == 0 &&
(unsigned char) optarg[1] >= 64 && (unsigned char) optarg[1] < 128)
@ -341,23 +355,26 @@ main(int ac, char **av)
exit(1);
}
break;
case 'c':
options.cipher = cipher_number(optarg);
if (options.cipher == -1) {
fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
exit(1);
if (ciphers_valid(optarg)) {
/* SSH2 only */
options.ciphers = xstrdup(optarg);
options.cipher = SSH_CIPHER_ILLEGAL;
} else {
/* SSH1 only */
options.cipher = cipher_number(optarg);
if (options.cipher == -1) {
fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
exit(1);
}
}
break;
case 'p':
options.port = atoi(optarg);
break;
case 'l':
options.user = optarg;
break;
case 'R':
if (sscanf(optarg, "%hu/%255[^/]/%hu", &fwd_port, buf,
&fwd_host_port) != 3 &&
@ -369,7 +386,6 @@ main(int ac, char **av)
}
add_remote_forward(&options, fwd_port, buf, fwd_host_port);
break;
case 'L':
if (sscanf(optarg, "%hu/%255[^/]/%hu", &fwd_port, buf,
&fwd_host_port) != 3 &&
@ -381,18 +397,22 @@ main(int ac, char **av)
}
add_local_forward(&options, fwd_port, buf, fwd_host_port);
break;
case 'C':
options.compression = 1;
break;
case 'N':
no_shell_flag = 1;
no_tty_flag = 1;
break;
case 'T':
no_tty_flag = 1;
break;
case 'o':
dummy = 1;
if (process_config_line(&options, host ? host : "", optarg,
"command-line", 0, &dummy) != 0)
exit(1);
break;
default:
usage();
}
@ -402,15 +422,8 @@ main(int ac, char **av)
if (!host)
usage();
/* check if RSA support exists */
if (rsa_alive() == 0) {
extern char *__progname;
OpenSSL_add_all_algorithms();
fprintf(stderr,
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
__progname);
exit(1);
}
/* Initialize the command to execute on remote host. */
buffer_init(&command);
@ -446,6 +459,10 @@ main(int ac, char **av)
fprintf(stderr, "Pseudo-terminal will not be allocated because stdin is not a terminal.\n");
tty_flag = 0;
}
/* force */
if (no_tty_flag)
tty_flag = 0;
/* Get user data. */
pw = getpwuid(original_real_uid);
if (!pw) {
@ -479,6 +496,20 @@ main(int ac, char **av)
/* reinit */
log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
/* check if RSA support exists */
if ((options.protocol & SSH_PROTO_1) &&
rsa_alive() == 0) {
log("%s: no RSA support in libssl and libcrypto. See ssl(8).",
__progname);
log("Disabling protocol version 1");
options.protocol &= ~ (SSH_PROTO_1|SSH_PROTO_1_PREFERRED);
}
if (! options.protocol & (SSH_PROTO_1|SSH_PROTO_2)) {
fprintf(stderr, "%s: No protocol version available.\n",
__progname);
exit(1);
}
if (options.user == NULL)
options.user = xstrdup(pw->pw_name);
@ -545,9 +576,12 @@ main(int ac, char **av)
* authentication. This must be done before releasing extra
* privileges, because the file is only readable by root.
*/
if (ok) {
if (ok && (options.protocol & SSH_PROTO_1)) {
Key k;
host_private_key = RSA_new();
if (load_private_key(HOST_KEY_FILE, "", host_private_key, NULL))
k.type = KEY_RSA;
k.rsa = host_private_key;
if (load_private_key(HOST_KEY_FILE, "", &k, NULL))
host_private_key_loaded = 1;
}
/*
@ -593,15 +627,22 @@ main(int ac, char **av)
exit(1);
}
/* Expand ~ in options.identity_files. */
/* XXX mem-leaks */
for (i = 0; i < options.num_identity_files; i++)
options.identity_files[i] =
tilde_expand_filename(options.identity_files[i], original_real_uid);
for (i = 0; i < options.num_identity_files2; i++)
options.identity_files2[i] =
tilde_expand_filename(options.identity_files2[i], original_real_uid);
/* Expand ~ in known host file names. */
options.system_hostfile = tilde_expand_filename(options.system_hostfile,
original_real_uid);
original_real_uid);
options.user_hostfile = tilde_expand_filename(options.user_hostfile,
original_real_uid);
original_real_uid);
options.system_hostfile2 = tilde_expand_filename(options.system_hostfile2,
original_real_uid);
options.user_hostfile2 = tilde_expand_filename(options.user_hostfile2,
original_real_uid);
/* Log into the remote system. This never returns if the login fails. */
ssh_login(host_private_key_loaded, host_private_key,
@ -611,6 +652,62 @@ main(int ac, char **av)
if (host_private_key_loaded)
RSA_free(host_private_key); /* Destroys contents safely */
exit_status = compat20 ? ssh_session2() : ssh_session();
packet_close();
return exit_status;
}
void
x11_get_proto(char *proto, int proto_len, char *data, int data_len)
{
char line[512];
FILE *f;
int got_data = 0, i;
#ifdef XAUTH_PATH
/* Try to get Xauthority information for the display. */
snprintf(line, sizeof line, "%.100s list %.200s 2>/dev/null",
XAUTH_PATH, getenv("DISPLAY"));
f = popen(line, "r");
if (f && fgets(line, sizeof(line), f) &&
sscanf(line, "%*s %s %s", proto, data) == 2)
got_data = 1;
if (f)
pclose(f);
#endif /* XAUTH_PATH */
/*
* If we didn't get authentication data, just make up some
* data. The forwarding code will check the validity of the
* response anyway, and substitute this data. The X11
* server, however, will ignore this fake data and use
* whatever authentication mechanisms it was using otherwise
* for the local connection.
*/
if (!got_data) {
u_int32_t rand = 0;
strlcpy(proto, "MIT-MAGIC-COOKIE-1", proto_len);
for (i = 0; i < 16; i++) {
if (i % 4 == 0)
rand = arc4random();
snprintf(data + 2 * i, data_len - 2 * i, "%02x", rand & 0xff);
rand >>= 8;
}
}
}
int
ssh_session(void)
{
int type;
int i;
int plen;
int interactive = 0;
int have_tty = 0;
struct winsize ws;
int authfd;
char *cp;
/* Enable compression if requested. */
if (options.compression) {
debug("Requesting compression at level %d.", options.compression_level);
@ -664,7 +761,7 @@ main(int ac, char **av)
type = packet_read(&plen);
if (type == SSH_SMSG_SUCCESS) {
interactive = 1;
have_pty = 1;
have_tty = 1;
} else if (type == SSH_SMSG_FAILURE)
log("Warning: Remote host failed or refused to allocate a pseudo tty.");
else
@ -672,56 +769,22 @@ main(int ac, char **av)
}
/* Request X11 forwarding if enabled and DISPLAY is set. */
if (options.forward_x11 && getenv("DISPLAY") != NULL) {
char line[512], proto[512], data[512];
FILE *f;
int forwarded = 0, got_data = 0, i;
#ifdef XAUTH_PATH
/* Try to get Xauthority information for the display. */
snprintf(line, sizeof line, "%.100s list %.200s 2>/dev/null",
XAUTH_PATH, getenv("DISPLAY"));
f = popen(line, "r");
if (f && fgets(line, sizeof(line), f) &&
sscanf(line, "%*s %s %s", proto, data) == 2)
got_data = 1;
if (f)
pclose(f);
#endif /* XAUTH_PATH */
/*
* If we didn't get authentication data, just make up some
* data. The forwarding code will check the validity of the
* response anyway, and substitute this data. The X11
* server, however, will ignore this fake data and use
* whatever authentication mechanisms it was using otherwise
* for the local connection.
*/
if (!got_data) {
u_int32_t rand = 0;
strlcpy(proto, "MIT-MAGIC-COOKIE-1", sizeof proto);
for (i = 0; i < 16; i++) {
if (i % 4 == 0)
rand = arc4random();
snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", rand & 0xff);
rand >>= 8;
}
}
/*
* Got local authentication reasonable information. Request
* forwarding with authentication spoofing.
*/
char proto[512], data[512];
/* Get reasonable local authentication information. */
x11_get_proto(proto, sizeof proto, data, sizeof data);
/* Request forwarding with authentication spoofing. */
debug("Requesting X11 forwarding with authentication spoofing.");
x11_request_forwarding_with_spoofing(proto, data);
x11_request_forwarding_with_spoofing(0, proto, data);
/* Read response from the server. */
type = packet_read(&plen);
if (type == SSH_SMSG_SUCCESS) {
forwarded = 1;
interactive = 1;
} else if (type == SSH_SMSG_FAILURE)
} else if (type == SSH_SMSG_FAILURE) {
log("Warning: Remote host denied X11 forwarding.");
else
} else {
packet_disconnect("Protocol error waiting for X11 forwarding");
}
}
/* Tell the packet module whether this is an interactive session. */
packet_set_interactive(interactive, options.keepalives);
@ -751,7 +814,7 @@ main(int ac, char **av)
options.local_forwards[i].host,
options.local_forwards[i].host_port);
channel_request_local_forwarding(options.local_forwards[i].port,
options.local_forwards[i].host,
options.local_forwards[i].host,
options.local_forwards[i].host_port,
options.gateway_ports);
}
@ -764,11 +827,11 @@ main(int ac, char **av)
options.remote_forwards[i].host_port);
channel_request_remote_forwarding(options.remote_forwards[i].port,
options.remote_forwards[i].host,
options.remote_forwards[i].host_port);
options.remote_forwards[i].host_port);
}
/* If requested, let ssh continue in the background. */
if (fork_after_authentication_flag)
if (fork_after_authentication_flag)
if (daemon(1, 1) < 0)
fatal("daemon() failed: %.200s", strerror(errno));
@ -793,11 +856,114 @@ main(int ac, char **av)
}
/* Enter the interactive session. */
exit_status = client_loop(have_pty, tty_flag ? options.escape_char : -1);
/* Close the connection to the remote host. */
packet_close();
/* Exit with the status returned by the program on the remote side. */
exit(exit_status);
return client_loop(have_tty, tty_flag ? options.escape_char : -1);
}
void
init_local_fwd(void)
{
int i;
/* Initiate local TCP/IP port forwardings. */
for (i = 0; i < options.num_local_forwards; i++) {
debug("Connections to local port %d forwarded to remote address %.200s:%d",
options.local_forwards[i].port,
options.local_forwards[i].host,
options.local_forwards[i].host_port);
channel_request_local_forwarding(options.local_forwards[i].port,
options.local_forwards[i].host,
options.local_forwards[i].host_port,
options.gateway_ports);
}
}
extern void client_set_session_ident(int id);
void
client_init(int id, void *arg)
{
int len;
debug("client_init id %d arg %d", id, (int)arg);
if (no_shell_flag)
goto done;
if (tty_flag) {
struct winsize ws;
char *cp;
cp = getenv("TERM");
if (!cp)
cp = "";
/* Store window size in the packet. */
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
memset(&ws, 0, sizeof(ws));
channel_request_start(id, "pty-req", 0);
packet_put_cstring(cp);
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_put_cstring(""); /* XXX: encode terminal modes */
packet_send();
/* XXX wait for reply */
}
if (options.forward_x11 &&
getenv("DISPLAY") != NULL) {
char proto[512], data[512];
/* Get reasonable local authentication information. */
x11_get_proto(proto, sizeof proto, data, sizeof data);
/* Request forwarding with authentication spoofing. */
debug("Requesting X11 forwarding with authentication spoofing.");
x11_request_forwarding_with_spoofing(id, proto, data);
/* XXX wait for reply */
}
len = buffer_len(&command);
if (len > 0) {
if (len > 900)
len = 900;
debug("Sending command: %.*s", len, buffer_ptr(&command));
channel_request_start(id, "exec", 0);
packet_put_string(buffer_ptr(&command), len);
packet_send();
} else {
channel_request(id, "shell", 0);
}
/* channel_callback(id, SSH2_MSG_OPEN_CONFIGMATION, client_init, 0); */
done:
/* register different callback, etc. XXX */
client_set_session_ident(id);
}
int
ssh_session2(void)
{
int window, packetmax, id;
int in = dup(STDIN_FILENO);
int out = dup(STDOUT_FILENO);
int err = dup(STDERR_FILENO);
if (in < 0 || out < 0 || err < 0)
fatal("dump in/out/err failed");
/* should be pre-session */
init_local_fwd();
window = 32*1024;
if (tty_flag) {
packetmax = window/8;
} else {
window *= 2;
packetmax = window/2;
}
id = channel_new(
"session", SSH_CHANNEL_OPENING, in, out, err,
window, packetmax, CHAN_EXTENDED_WRITE, xstrdup("client-session"));
channel_open(id);
channel_register_callback(id, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, client_init, (void *)0);
return client_loop(tty_flag, tty_flag ? options.escape_char : -1);
}

View File

@ -1,19 +1,19 @@
/*
*
*
* ssh.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 17:09:37 1995 ylo
*
*
* Generic header file for ssh.
*
*
*/
/* RCSID("$Id: ssh.h,v 1.34 2000/03/23 22:15:33 markus Exp $"); */
/* RCSID("$Id: ssh.h,v 1.45 2000/05/08 17:12:16 markus Exp $"); */
#ifndef SSH_H
#define SSH_H
@ -22,6 +22,7 @@
#include "cipher.h"
/*
* XXX
* The default cipher used if IDEA is not supported by the remote host. It is
* recommended that this be one of the mandatory ciphers (DES, 3DES), though
* that is not required.
@ -46,14 +47,16 @@
/*
* Major protocol version. Different version indicates major incompatiblity
* that prevents communication.
*/
#define PROTOCOL_MAJOR 1
/*
*
* Minor protocol version. Different version indicates minor incompatibility
* that does not prevent interoperation.
*/
#define PROTOCOL_MINOR 5
#define PROTOCOL_MAJOR_1 1
#define PROTOCOL_MINOR_1 5
/* We support both SSH1 and SSH2 */
#define PROTOCOL_MAJOR_2 2
#define PROTOCOL_MINOR_2 0
/*
* Name for the service. The port named by this service overrides the
@ -69,6 +72,7 @@
* world-readable.
*/
#define SSH_SYSTEM_HOSTFILE ETCDIR "/ssh_known_hosts"
#define SSH_SYSTEM_HOSTFILE2 ETCDIR "/ssh_known_hosts2"
/*
* Of these, ssh_host_key must be readable only by root, whereas ssh_config
@ -77,6 +81,7 @@
#define HOST_KEY_FILE ETCDIR "/ssh_host_key"
#define SERVER_CONFIG_FILE ETCDIR "/sshd_config"
#define HOST_CONFIG_FILE ETCDIR "/ssh_config"
#define HOST_DSA_KEY_FILE ETCDIR "/ssh_host_dsa_key"
#define SSH_PROGRAM "/usr/bin/ssh"
@ -98,12 +103,14 @@
* contain anything particularly secret.
*/
#define SSH_USER_HOSTFILE "~/.ssh/known_hosts"
#define SSH_USER_HOSTFILE2 "~/.ssh/known_hosts2"
/*
* Name of the default file containing client-side authentication key. This
* file should only be readable by the user him/herself.
*/
#define SSH_CLIENT_IDENTITY ".ssh/identity"
#define SSH_CLIENT_ID_DSA ".ssh/id_dsa"
/*
* Configuration file in user\'s home directory. This file need not be
@ -122,6 +129,7 @@
* running as root.)
*/
#define SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys"
#define SSH_USER_PERMITTED_KEYS2 ".ssh/authorized_keys2"
/*
* Per-user and system-wide ssh "rc" files. These files are executed with
@ -251,7 +259,7 @@
* information is not available. This must be called before record_login.
* The host from which the user logged in is stored in buf.
*/
unsigned long
unsigned long
get_last_login_time(uid_t uid, const char *logname,
char *buf, unsigned int bufsize);
@ -259,15 +267,15 @@ get_last_login_time(uid_t uid, const char *logname,
* Records that the user has logged in. This does many things normally done
* by login(1).
*/
void
record_login(int pid, const char *ttyname, const char *user, uid_t uid,
void
record_login(pid_t pid, const char *ttyname, const char *user, uid_t uid,
const char *host, struct sockaddr *addr);
/*
* Records that the user has logged out. This does many thigs normally done
* by login(1) or init.
*/
void record_logout(int pid, const char *ttyname);
void record_logout(pid_t pid, const char *ttyname);
/*------------ definitions for sshconnect.c ----------*/
@ -280,7 +288,7 @@ void record_logout(int pid, const char *ttyname);
* and zero on failure. If the connection is successful, this calls
* packet_set_connection for the connection.
*/
int
int
ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
u_short port, int connection_attempts,
int anonymous, uid_t original_real_uid,
@ -295,7 +303,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
* references from the packet module).
*/
void
void
ssh_login(int host_key_valid, RSA * host_key, const char *host,
struct sockaddr * hostaddr, uid_t original_real_uid);
@ -312,7 +320,7 @@ int auth_rhosts(struct passwd * pw, const char *client_user);
* Tries to authenticate the user using the .rhosts file and the host using
* its host key. Returns true if authentication succeeds.
*/
int
int
auth_rhosts_rsa(struct passwd * pw, const char *client_user, RSA* client_host_key);
/*
@ -375,36 +383,6 @@ int auth_rsa_challenge_dialog(RSA *pk);
*/
char *read_passphrase(const char *prompt, int from_stdin);
/*
* Saves the authentication (private) key in a file, encrypting it with
* passphrase. 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,
RSA * 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, RSA * 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,
RSA * private_key, char **comment_return);
/*------------ Definitions for logging. -----------------------*/
@ -461,174 +439,7 @@ void fatal_add_cleanup(void (*proc) (void *context), void *context);
/* Removes a cleanup function to be called at fatal(). */
void fatal_remove_cleanup(void (*proc) (void *context), void *context);
/*---------------- definitions for channels ------------------*/
/* 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);
/*
* This is called when a packet of type CHANNEL_DATA has just been received.
* The message type has already been consumed, but channel number and data is
* still there.
*/
void channel_input_data(int payload_len);
/* Returns true if no channel has too much buffered data. */
int channel_not_very_much_buffered_data(void);
/* This is called after receiving CHANNEL_CLOSE. */
void channel_input_close(void);
/* This is called after receiving CHANNEL_CLOSE_CONFIRMATION. */
void channel_input_close_confirmation(void);
/* This is called after receiving CHANNEL_OPEN_CONFIRMATION. */
void channel_input_open_confirmation(void);
/* This is called after receiving CHANNEL_OPEN_FAILURE from the other side. */
void channel_input_open_failure(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);
/*
* This is called after receiving PORT_OPEN message. This attempts to
* connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION
* or CHANNEL_OPEN_FAILURE.
*/
void channel_input_port_open(int payload_len);
/*
* 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 payload_len);
/*
* 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(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(void);
/*
* Returns true if the given string matches the pattern (which may contain ?
* and * as wildcards), and zero if it does not match.
*/
int match_pattern(const char *s, const char *pattern);
/* ---- misc */
/*
* Expands tildes in the file name. Returns data allocated by xmalloc.
@ -643,7 +454,8 @@ char *tilde_expand_filename(const char *filename, uid_t my_uid);
* (of the child program), and reads from stdout and stderr (of the child
* program).
*/
void server_loop(int pid, int fdin, int fdout, int fderr);
void server_loop(pid_t pid, int fdin, int fdout, int fderr);
void server_loop2(void);
/* Client side main loop for the interactive session. */
int client_loop(int have_pty, int escape_char);
@ -678,7 +490,7 @@ int auth_krb4_password(struct passwd * pw, const char *password);
int auth_kerberos_tgt(struct passwd * pw, const char *string);
int auth_afs_token(struct passwd * pw, const char *token_string);
int creds_to_radix(CREDENTIALS * creds, unsigned char *buf);
int creds_to_radix(CREDENTIALS * creds, unsigned char *buf, size_t buflen);
int radix_to_creds(const char *buf, CREDENTIALS * creds);
#endif /* AFS */

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

@ -26,5 +26,6 @@
# StrictHostKeyChecking no
# IdentityFile ~/.ssh/identity
# Port 22
# Protocol 2,1
# Cipher blowfish
# EscapeChar ~

File diff suppressed because it is too large Load Diff

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

@ -9,7 +9,7 @@
.\"
.\" Created: Sat Apr 22 21:55:14 1995 ylo
.\"
.\" $Id: sshd.8,v 1.37 2000/03/24 03:04:46 brad Exp $
.\" $Id: sshd.8,v 1.51 2000/05/08 17:42:31 hugh Exp $
.\"
.Dd September 25, 1999
.Dt SSHD 8
@ -27,11 +27,11 @@
.Op Fl k Ar key_gen_time
.Op Fl p Ar port
.Op Fl V Ar client_protocol_id
.Sh DESCRIPTION
.Sh DESCRIPTION
.Nm
(Secure Shell Daemon) is the daemon program for
(Secure Shell Daemon) is the daemon program for
.Xr ssh 1 .
Together these programs replace rlogin and rsh programs, and
Together these programs replace rlogin and rsh, and
provide secure encrypted communications between two untrusted hosts
over an insecure network.
The programs are intended to be as easy to
@ -39,16 +39,21 @@ install and use as possible.
.Pp
.Nm
is the daemon that listens for connections from clients.
It is normally started at boot from
It is normally started at boot from
.Pa /etc/rc .
It forks a new
daemon for each incoming connection.
The forked daemons handle
key exchange, encryption, authentication, command execution,
and data exchange.
.Pp
This implementation of
.Nm
supports both SSH protocol version 1 and 2 simultaneously.
.Nm
works as follows.
.Pp
.Ss SSH protocol version 1
.Pp
Each host has a host-specific RSA key
(normally 1024 bits) used to identify the host.
Additionally, when
@ -56,20 +61,20 @@ the daemon starts, it generates a server RSA key (normally 768 bits).
This key is normally regenerated every hour if it has been used, and
is never stored on disk.
.Pp
Whenever a client connects the daemon, the daemon sends its host
and server public keys to the client.
Whenever a client connects the daemon responds with its public
host and server keys.
The client compares the
host key against its own database to verify that it has not changed.
RSA host key against its own database to verify that it has not changed.
The client then generates a 256 bit random number.
It encrypts this
random number using both the host key and the server key, and sends
the encrypted number to the server.
Both sides then start to use this
Both sides then use this
random number as a session key which is used to encrypt all further
communications in the session.
The rest of the session is encrypted
using a conventional cipher, currently Blowfish and 3DES, with 3DES
being is used by default.
using a conventional cipher, currently Blowfish or 3DES, with 3DES
being used by default.
The client selects the encryption algorithm
to use from those offered by the server.
.Pp
@ -95,7 +100,29 @@ are disabled (thus completely disabling
.Xr rlogin 1
and
.Xr rsh 1
into that machine).
into the machine).
.Pp
.Ss SSH protocol version 2
.Pp
Version 2 works similar:
Each host has a host-specific DSA key used to identify the host.
However, when the daemon starts, it does not generate a server key.
Forward security is provided through a Diffie-Hellman key agreement.
This key agreement results in a shared session key.
The rest of the session is encrypted
using a symmetric cipher, currently
Blowfish, 3DES or CAST128 in CBC mode or Arcfour.
The client selects the encryption algorithm
to use from those offered by the server.
Additionally, session integrity is provided
through a cryptographic message authentication code
(hmac-sha1 or hmac-md5).
.Pp
Protocol version 2 provides a public key based
user authentication method (DSAAuthentication)
and conventional password authentication.
.Pp
.Ss Command execution and data forwarding
.Pp
If the client successfully authenticates itself, a dialog for
preparing the session is entered.
@ -148,7 +175,7 @@ If the client fails to authenticate the user within
this many seconds, the server disconnects and exits.
A value of zero indicates no limit.
.It Fl h Ar host_key_file
Specifies the file from which the host key is read (default
Specifies the file from which the RSA host key is read (default
.Pa /etc/ssh_host_key ) .
This option must be given if
.Nm
@ -157,7 +184,7 @@ host file is normally not readable by anyone but root).
.It Fl i
Specifies that
.Nm
is being run from inetd.
is being run from inetd.
.Nm
is normally not run
from inetd because it needs to generate the server key before it can
@ -188,9 +215,9 @@ authentication, and termination of each connection is logged.
Do not print an error message if RSA support is missing.
.It Fl V Ar client_protocol_id
SSH2 compatibility mode.
When this options is specified
When this option is specified
.Nm
assumes the client has sent the given version string
assumes the client has sent the supplied version string
and skips the
Protocol Version Identification Exchange.
.It Fl 4
@ -204,7 +231,7 @@ to use IPv6 addresses only.
.El
.Sh CONFIGURATION FILE
.Nm
reads configuration data from
reads configuration data from
.Pa /etc/sshd_config
(or the file specified with
.Fl f
@ -246,6 +273,11 @@ wildcards in the patterns.
Only user names are valid, a numerical user ID isn't recognized.
By default login is allowed regardless of the user name.
.Pp
.It Cm Ciphers
Specifies the ciphers allowed for protocol version 2.
Multiple ciphers must be comma-separated.
The default is
.Dq 3des-cbc,blowfish-cbc,arcfour,cast128-cbc .
.It Cm CheckMail
Specifies whether
.Nm
@ -275,23 +307,45 @@ and
can be used as wildcards in the patterns.
Only user names are valid, a numerical user ID isn't recognized.
By default login is allowed regardless of the user name.
.It Cm HostKey
Specifies the file containing the private host key (default
.Pa /etc/ssh_host_key ) .
.It Cm DSAAuthentication
Specifies whether DSA authentication is allowed.
The default is
.Dq yes .
Note that this option applies to protocol version 2 only.
.It Cm GatewayPorts
Specifies whether remote hosts are allowed to connect to ports
forwarded for the client.
The argument must be
.Dq yes
or
.Dq no .
The default is
.Dq no .
.It Cm HostDsaKey
Specifies the file containing the private DSA host key (default
.Pa /etc/ssh_host_dsa_key )
used by SSH protocol 2.0.
Note that
.Nm
does not start if this file is group/world-accessible.
disables protocol 2.0 if this file is group/world-accessible.
.It Cm HostKey
Specifies the file containing the private RSA host key (default
.Pa /etc/ssh_host_key )
used by SSH protocols 1.3 and 1.5.
Note that
.Nm
disables protocols 1.3 and 1.5 if this file is group/world-accessible.
.It Cm IgnoreRhosts
Specifies that
.Pa .rhosts
and
and
.Pa .shosts
files will not be used in authentication.
.Pa /etc/hosts.equiv
and
.Pa /etc/shosts.equiv
.Pa /etc/shosts.equiv
are still used.
The default is
The default is
.Dq yes .
.It Cm IgnoreUserKnownHosts
Specifies whether
@ -310,7 +364,7 @@ of the machines will be properly noticed.
However, this means that
connections will die if the route is down temporarily, and some people
find it annoying.
On the other hand, if keepalives are not send,
On the other hand, if keepalives are not sent,
sessions may hang indefinitely on the server, leaving
.Dq ghost
users and consuming server resources.
@ -342,7 +396,7 @@ Default is
.Dq yes .
.It Cm KerberosTgtPassing
Specifies whether a Kerberos TGT may be forwarded to the server.
Default is
Default is
.Dq no ,
as this only works when the Kerberos KDC is actually an AFS kaserver.
.It Cm KerberosTicketCleanup
@ -385,6 +439,7 @@ and is not recommended.
Specifies whether password authentication is allowed.
The default is
.Dq yes .
Note that this option applies to both protocol version 1 and 2.
.It Cm PermitEmptyPasswords
When password authentication is allowed, it specifies whether the
server allows login to accounts with empty password strings.
@ -410,6 +465,12 @@ option has been
specified will be allowed regardless of the value of this setting
(which may be useful for taking remote backups even if root login is
normally not allowed).
.It Cm PidFile
Specifies the file that contains the process identifier of the
.Nm
daemon.
The default is
.Pa /var/run/sshd.pid .
.It Cm Port
Specifies the port number that
.Nm
@ -419,7 +480,7 @@ Multiple options of this type are permitted.
.It Cm PrintMotd
Specifies whether
.Nm
should print
should print
.Pa /etc/motd
when a user logs in interactively.
(On some systems it is also printed by the shell,
@ -427,6 +488,17 @@ when a user logs in interactively.
or equivalent.)
The default is
.Dq yes .
.It Cm Protocol
Specifies the protocol versions
.Nm
should support.
The possible values are
.Dq 1
and
.Dq 2 .
Multiple versions must be comma-separated.
The default is
.Dq 1 .
.It Cm RandomSeed
Obsolete.
Random number generation uses other techniques.
@ -449,12 +521,13 @@ The default is
Specifies whether pure RSA authentication is allowed.
The default is
.Dq yes .
Note that this option applies to protocol version 1 only.
.It Cm ServerKeyBits
Defines the number of bits in the server key.
The minimum value is 512, and the default is 768.
.It Cm SkeyAuthentication
Specifies whether
.Xr skey 1
.Xr skey 1
authentication is allowed.
The default is
.Dq yes .
@ -504,12 +577,12 @@ does the following:
.Bl -enum -offset indent
.It
If the login is on a tty, and no command has been specified,
prints last login time and
prints last login time and
.Pa /etc/motd
(unless prevented in the configuration file or by
.Pa $HOME/.hushlogin ;
see the
.Sx FILES
.Sx FILES
section).
.It
If the login is on a tty, records login time.
@ -543,10 +616,14 @@ authentication protocol and cookie in standard input.
Runs user's shell or command.
.El
.Sh AUTHORIZED_KEYS FILE FORMAT
The
The
.Pa $HOME/.ssh/authorized_keys
file lists the RSA keys that are
permitted for RSA authentication.
permitted for RSA authentication in SSH protocols 1.3 and 1.5
Similarly, the
.Pa $HOME/.ssh/authorized_keys2
file lists the DSA keys that are
permitted for DSA authentication in SSH protocol 2.0.
Each line of the file contains one
key (empty lines and lines starting with a
.Ql #
@ -602,8 +679,8 @@ A quote may be included in the command by quoting it with a backslash.
This option might be useful
to restrict certain RSA keys to perform just a specific operation.
An example might be a key that permits remote backups but nothing else.
Notice that the client may specify TCP/IP and/or X11
forwardings unless they are explicitly prohibited.
Note that the client may specify TCP/IP and/or X11
forwarding unless they are explicitly prohibited.
.It Cm environment="NAME=value"
Specifies that the string is to be added to the environment when
logging in using this key.
@ -632,10 +709,12 @@ from="*.niksula.hut.fi,!pc.niksula.hut.fi" 1024 35 23.\|.\|.\|2334 ylo@niksula
.Pp
command="dump /home",no-pty,no-port-forwarding 1024 33 23.\|.\|.\|2323 backup.hut.fi
.Sh SSH_KNOWN_HOSTS FILE FORMAT
The
.Pa /etc/ssh_known_hosts
and
.Pa $HOME/.ssh/known_hosts
The
.Pa /etc/ssh_known_hosts ,
.Pa /etc/ssh_known_hosts2 ,
.Pa $HOME/.ssh/known_hosts ,
and
.Pa $HOME/.ssh/known_hosts2
files contain host public keys for all known hosts.
The global file should
be prepared by the administrator (optional), and the per-user file is
@ -656,7 +735,7 @@ to indicate negation: if the host name matches a negated
pattern, it is not accepted (by that line) even if it matched another
pattern on the line.
.Pp
Bits, exponent, and modulus are taken directly from the host key; they
Bits, exponent, and modulus are taken directly from the RSA host key; they
can be obtained, e.g., from
.Pa /etc/ssh_host_key.pub .
The optional comment field continues to the end of the line, and is not used.
@ -679,7 +758,7 @@ accepted if valid information can be found from either file.
Note that the lines in these files are typically hundreds of characters
long, and you definitely don't want to type in the host keys by hand.
Rather, generate them by a script
or by taking
or by taking
.Pa /etc/ssh_host_key.pub
and adding the host names at the front.
.Ss Examples
@ -722,6 +801,21 @@ it being world-readable if the user's home directory resides on an NFS
volume).
It is recommended that it not be accessible by others.
The format of this file is described above.
Users will place the contents of their
.Pa identity.pub
files into this file, as described in
.Xr ssh-keygen 1 .
.It Pa $HOME/.ssh/authorized_keys2
Lists the DSA keys that can be used to log into the user's account.
This file must be readable by root (which may on some machines imply
it being world-readable if the user's home directory resides on an NFS
volume).
It is recommended that it not be accessible by others.
The format of this file is described above.
Users will place the contents of their
.Pa id_dsa.pub
files into this file, as described in
.Xr ssh-keygen 1 .
.It Pa "/etc/ssh_known_hosts" and "$HOME/.ssh/known_hosts"
These files are consulted when using rhosts with RSA host
authentication to check the public key of the host.
@ -734,7 +828,7 @@ should be world-readable, and
.Pa $HOME/.ssh/known_hosts
can but need not be world-readable.
.It Pa /etc/nologin
If this file exists,
If this file exists,
.Nm
refuses to let anyone except root log in.
The contents of the file
@ -853,6 +947,7 @@ but with bugs removed and newer features re-added.
Rapidly after the
1.2.12 release, newer versions of the original ssh bore successively
more restrictive licenses, and thus demand for a free version was born.
.Pp
This version of OpenSSH
.Bl -bullet
.It
@ -862,10 +957,10 @@ directly removed from the source code; any licensed or patented components
are chosen from
external libraries.
.It
has been updated to support ssh protocol 1.5, making it compatible with
all other ssh protocol 1 clients and servers.
has been updated to support SSH protocol 1.5 and 2, making it compatible with
all other SSH clients and servers.
.It
contains added support for
contains added support for
.Xr kerberos 8
authentication and ticket passing.
.It
@ -876,12 +971,17 @@ supports one-time password authentication with
The libraries described in
.Xr ssl 8
are required for proper operation.
.Pp
OpenSSH has been created by Aaron Campbell, Bob Beck, Markus Friedl,
Niels Provos, Theo de Raadt, and Dug Song.
.Pp
The support for SSH protocol 2 was written by Markus Friedl.
.Sh SEE ALSO
.Xr rlogin 1 ,
.Xr rsh 1 ,
.Xr scp 1 ,
.Xr ssh 1 ,
.Xr ssh-add 1 ,
.Xr ssh-agent 1 ,
.Xr ssh-keygen 1 ,
.Xr ssl 8
.Xr ssl 8 ,
.Xr rlogin 1 ,
.Xr rsh 1

File diff suppressed because it is too large Load Diff

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

@ -1,6 +1,7 @@
# This is ssh server systemwide configuration file.
Port 22
#Protocol 2,1
#ListenAddress 0.0.0.0
#ListenAddress ::
HostKey /etc/ssh_host_key

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"

Some files were not shown because too many files have changed in this diff Show More