- Merge big update to OpenSSH-2.0 from OpenBSD CVS

[README.openssh2]
   - interop w/ F-secure windows client
   - sync documentation
   - ssh_host_dsa_key not ssh_dsa_key
   [auth-rsa.c]
   - missing fclose
   [auth.c authfile.c compat.c dsa.c dsa.h hostfile.c key.c key.h radix.c]
   [readconf.c readconf.h ssh-add.c ssh-keygen.c ssh.c ssh.h sshconnect.c]
   [sshd.c uuencode.c uuencode.h authfile.h]
   - add DSA pubkey auth and other SSH2 fixes.  use ssh-keygen -[xX]
     for trading keys with the real and the original SSH, directly from the
     people who invented the SSH protocol.
   [auth.c auth.h authfile.c sshconnect.c auth1.c auth2.c sshconnect.h]
   [sshconnect1.c sshconnect2.c]
   - split auth/sshconnect in one file per protocol version
   [sshconnect2.c]
   - remove debug
   [uuencode.c]
   - add trailing =
   [version.h]
   - OpenSSH-2.0
   [ssh-keygen.1 ssh-keygen.c]
   - add -R flag: exit code indicates if RSA is alive
   [sshd.c]
   - remove unused
     silent if -Q is specified
   [ssh.h]
   - host key becomes /etc/ssh_host_dsa_key
   [readconf.c servconf.c ]
   - ssh/sshd default to proto 1 and 2
   [uuencode.c]
   - remove debug
   [auth2.c ssh-keygen.c sshconnect2.c sshd.c]
   - xfree DSA blobs
   [auth2.c serverloop.c session.c]
   - cleanup logging for sshd/2, respect PasswordAuth no
   [sshconnect2.c]
   - less debug, respect .ssh/config
   [README.openssh2 channels.c channels.h]
   - clientloop.c session.c ssh.c
   - support for x11-fwding, client+server
This commit is contained in:
Damien Miller 2000-04-29 23:57:08 +10:00
parent 8117111a3c
commit eba71bab9b
35 changed files with 3545 additions and 2500 deletions

View File

@ -1,3 +1,47 @@
20000429
- Merge big update to OpenSSH-2.0 from OpenBSD CVS
[README.openssh2]
- interop w/ F-secure windows client
- sync documentation
- ssh_host_dsa_key not ssh_dsa_key
[auth-rsa.c]
- missing fclose
[auth.c authfile.c compat.c dsa.c dsa.h hostfile.c key.c key.h radix.c]
[readconf.c readconf.h ssh-add.c ssh-keygen.c ssh.c ssh.h sshconnect.c]
[sshd.c uuencode.c uuencode.h authfile.h]
- add DSA pubkey auth and other SSH2 fixes. use ssh-keygen -[xX]
for trading keys with the real and the original SSH, directly from the
people who invented the SSH protocol.
[auth.c auth.h authfile.c sshconnect.c auth1.c auth2.c sshconnect.h]
[sshconnect1.c sshconnect2.c]
- split auth/sshconnect in one file per protocol version
[sshconnect2.c]
- remove debug
[uuencode.c]
- add trailing =
[version.h]
- OpenSSH-2.0
[ssh-keygen.1 ssh-keygen.c]
- add -R flag: exit code indicates if RSA is alive
[sshd.c]
- remove unused
silent if -Q is specified
[ssh.h]
- host key becomes /etc/ssh_host_dsa_key
[readconf.c servconf.c ]
- ssh/sshd default to proto 1 and 2
[uuencode.c]
- remove debug
[auth2.c ssh-keygen.c sshconnect2.c sshd.c]
- xfree DSA blobs
[auth2.c serverloop.c session.c]
- cleanup logging for sshd/2, respect PasswordAuth no
[sshconnect2.c]
- less debug, respect .ssh/config
[README.openssh2 channels.c channels.h]
- clientloop.c session.c ssh.c
- support for x11-fwding, client+server
20000421 20000421
- Merge fix from OpenBSD CVS - Merge fix from OpenBSD CVS
[ssh-agent.c] [ssh-agent.c]

View File

@ -31,11 +31,11 @@ LDFLAGS=-L. @LDFLAGS@
TARGETS=ssh sshd ssh-add ssh-keygen ssh-agent scp $(EXTRA_TARGETS) TARGETS=ssh sshd ssh-add ssh-keygen ssh-agent scp $(EXTRA_TARGETS)
LIBOBJS= atomicio.o authfd.o authfile.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dispatch.o dsa.o fake-getaddrinfo.o fake-getnameinfo.o fingerprint.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o xmalloc.o LIBOBJS= atomicio.o authfd.o authfile.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dispatch.o dsa.o fake-getaddrinfo.o fake-getnameinfo.o fingerprint.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o
SSHOBJS= ssh.o sshconnect.o log-client.o readconf.o clientloop.o SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o log-client.o readconf.o clientloop.o
SSHDOBJS= sshd.o auth-rhosts.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o pty.o log-server.o login.o servconf.o serverloop.o bsd-login.o md5crypt.o session.o auth.o SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-rhosts.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o pty.o log-server.o login.o servconf.o serverloop.o bsd-login.o md5crypt.o session.o
TROFFMAN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8 TROFFMAN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8
CATMAN = scp.0 ssh-add.0 ssh-agent.0 ssh-keygen.0 ssh.0 sshd.0 CATMAN = scp.0 ssh-add.0 ssh-agent.0 ssh-keygen.0 ssh.0 sshd.0

View File

@ -1,13 +1,16 @@
$Id: README.openssh2,v 1.3 2000/04/12 07:45:43 markus Exp $ $Id: README.openssh2,v 1.6 2000/04/27 13:42:58 provos Exp $
howto: howto:
1) generate server key: 1) generate server key:
$ umask 077 $ ssh-keygen -d -f /etc/ssh_host_dsa_key -N ''
$ openssl dsaparam 1024 -out dsa1024.pem
$ openssl gendsa -out /etc/ssh_dsa_key dsa1024.pem -rand /dev/arandom
2) enable ssh2: 2) enable ssh2:
server: add 'Protocol 2,1' to /etc/sshd_config server: add 'Protocol 2,1' to /etc/sshd_config
client: ssh -o 'Protocol 2,1', or add to .ssh/config client: ssh -o 'Protocol 2,1', or add to .ssh/config
3) 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: works:
secsh-transport: works w/o rekey secsh-transport: works w/o rekey
@ -22,7 +25,7 @@ works:
key database in ~/.ssh/known_hosts with bits == 0 hack key database in ~/.ssh/known_hosts with bits == 0 hack
dss: signature works, keygen w/ openssl dss: signature works, keygen w/ openssl
client interops w/ sshd2, lshd client interops w/ sshd2, lshd
server interops w/ ssh2, lsh, ssh.com's Windows client, SecureCRT server interops w/ ssh2, lsh, ssh.com's Windows client, SecureCRT, F-Secure SSH Client 4.0
server supports multiple concurrent sessions (e.g. with SSH.com Windows client) server supports multiple concurrent sessions (e.g. with SSH.com Windows client)
todo: todo:
re-keying re-keying
@ -38,4 +41,4 @@ todo:
sftp sftp
-markus -markus
$Date: 2000/04/12 07:45:43 $ $Date: 2000/04/27 13:42:58 $

View File

@ -16,7 +16,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: auth-rsa.c,v 1.17 2000/04/16 02:31:49 damien Exp $"); RCSID("$Id: auth-rsa.c,v 1.18 2000/04/29 13:57:09 damien Exp $");
#include "rsa.h" #include "rsa.h"
#include "packet.h" #include "packet.h"
@ -185,6 +185,7 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
} }
} }
if (fail) { if (fail) {
fclose(f);
log(buf); log(buf);
packet_send_debug(buf); packet_send_debug(buf);
restore_uid(); restore_uid();

686
auth.c
View File

@ -5,7 +5,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: auth.c,v 1.4 2000/04/14 10:30:29 markus Exp $"); RCSID("$OpenBSD: auth.c,v 1.6 2000/04/26 21:28:31 markus Exp $");
#include "xmalloc.h" #include "xmalloc.h"
#include "rsa.h" #include "rsa.h"
@ -40,7 +40,7 @@ extern char *forced_command;
* If the user's shell is not executable, false will be returned. * If the user's shell is not executable, false will be returned.
* Otherwise true is returned. * Otherwise true is returned.
*/ */
static int int
allowed_user(struct passwd * pw) allowed_user(struct passwd * pw)
{ {
struct stat st; struct stat st;
@ -118,685 +118,3 @@ allowed_user(struct passwd * pw)
/* We found no reason not to let this user try to log on... */ /* We found no reason not to let this user try to log on... */
return 1; return 1;
} }
/*
* 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;
}
#define AUTH_FAIL_MAX 6
#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
/*
* 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());
#ifdef WITH_AIXAUTHENTICATE
if (strncmp(get_authname(type),"password",
strlen(get_authname(type))) == 0)
loginfailed(pw->pw_name,get_canonical_hostname(),"ssh");
#endif /* WITH_AIXAUTHENTICATE */
/* 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;
#ifndef SKEY
(void)packet_read(&plen);
#else /* SKEY */
int type = packet_read(&plen);
unsigned int dlen;
char *password, *skeyinfo;
/* Try to send a fake s/key challenge. */
if (options.skey_authentication == 1 &&
(skeyinfo = skey_fake_keyinfo(user)) != NULL) {
password = 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 = NULL, *password = NULL;
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);
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))
error("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);
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);
#ifdef USE_PAM
/* Do PAM auth with password */
authenticated = auth_pam_password(pw, password);
#else /* USE_PAM */
/* Try authentication with the password. */
authenticated = auth_password(pw, password);
#endif /* USE_PAM */
memset(password, 0, 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);
#ifdef USE_PAM
if (authenticated) {
if (!do_pam_account(pw->pw_name, client_user)) {
if (client_user != NULL) {
xfree(client_user);
client_user = NULL;
}
do_fake_authloop1(pw->pw_name);
}
return;
}
#else /* USE_PAM */
if (authenticated) {
return;
}
#endif /* USE_PAM */
if (client_user != NULL) {
xfree(client_user);
client_user = NULL;
}
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;
#ifdef WITH_AIXAUTHENTICATE
char *loginmsg;
#endif /* WITH_AIXAUTHENTICATE */
/* 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;
#ifdef USE_PAM
start_pam(pw);
#endif
/*
* 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 */
#ifdef USE_PAM
auth_pam_password(pw, "")) {
#else /* USE_PAM */
auth_password(pw, "")) {
#endif /* USE_PAM */
/* 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. */
#ifdef WITH_AIXAUTHENTICATE
loginsuccess(user,get_canonical_hostname(),"ssh",&loginmsg);
#endif /* WITH_AIXAUTHENTICATE */
packet_start(SSH_SMSG_SUCCESS);
packet_send();
packet_write_wait();
/* Perform session preparation. */
do_authenticated(pw);
}
void input_service_request(int type, int plen);
void input_userauth_request(int type, int plen);
void ssh2_pty_cleanup(void);
typedef struct Authctxt Authctxt;
struct Authctxt {
char *user;
char *service;
struct passwd pw;
int valid;
};
static Authctxt *authctxt = NULL;
static int userauth_success = 0;
struct passwd*
auth_get_user(void)
{
return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
}
struct passwd*
auth_set_user(char *u, char *s)
{
struct passwd *pw, *copy;
if (authctxt == NULL) {
authctxt = xmalloc(sizeof(*authctxt));
authctxt->valid = 0;
authctxt->user = xstrdup(u);
authctxt->service = xstrdup(s);
setproctitle("%s", u);
pw = getpwnam(u);
if (!pw || !allowed_user(pw)) {
log("auth_set_user: bad user %s", u);
return NULL;
}
#ifdef USE_PAM
start_pam(pw);
#endif
copy = &authctxt->pw;
memset(copy, 0, sizeof(*copy));
copy->pw_name = xstrdup(pw->pw_name);
copy->pw_passwd = xstrdup(pw->pw_passwd);
copy->pw_uid = pw->pw_uid;
copy->pw_gid = pw->pw_gid;
copy->pw_dir = xstrdup(pw->pw_dir);
copy->pw_shell = xstrdup(pw->pw_shell);
authctxt->valid = 1;
} else {
if (strcmp(u, authctxt->user) != 0 ||
strcmp(s, authctxt->service) != 0) {
log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
u, s, authctxt->user, authctxt->service);
return NULL;
}
}
return auth_get_user();
}
static void
protocol_error(int type, int plen)
{
log("auth: protocol error: type %d plen %d", type, plen);
packet_start(SSH2_MSG_UNIMPLEMENTED);
packet_put_int(0);
packet_send();
packet_write_wait();
}
void
input_service_request(int type, int plen)
{
unsigned int len;
int accept = 0;
char *service = packet_get_string(&len);
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 int try = 0;
unsigned int len;
int c, authenticated = 0;
char *user, *service, *method;
struct passwd *pw;
if (++try == AUTH_FAIL_MAX)
packet_disconnect("too many failed userauth_requests");
user = packet_get_string(&len);
service = packet_get_string(&len);
method = packet_get_string(&len);
debug("userauth-request for user %s service %s method %s", user, service, method);
/* XXX we only allow the ssh-connection service */
pw = auth_set_user(user, service);
if (pw && strcmp(service, "ssh-connection")==0) {
if (strcmp(method, "none") == 0 && try == 1) {
packet_done();
#ifdef USE_PAM
/* Do PAM auth with password */
authenticated = auth_pam_password(pw, "");
#else /* USE_PAM */
/* Try authentication with the password. */
authenticated = auth_password(pw, "");
#endif /* USE_PAM */
} else if (strcmp(method, "password") == 0) {
char *password;
c = packet_get_char();
if (c)
debug("password change not supported");
password = packet_get_string(&len);
packet_done();
#ifdef USE_PAM
/* Do PAM auth with password */
authenticated = auth_pam_password(pw, password);
#else /* USE_PAM */
/* Try authentication with the password. */
authenticated = auth_password(pw, password);
#endif /* USE_PAM */
memset(password, 0, len);
xfree(password);
} else if (strcmp(method, "publickey") == 0) {
/* XXX TODO */
char *pkalg, *pkblob, *sig;
int have_sig = packet_get_char();
pkalg = packet_get_string(&len);
pkblob = packet_get_string(&len);
if (have_sig) {
sig = packet_get_string(&len);
/* test for correct signature */
packet_done();
xfree(sig);
} else {
packet_done();
/* test whether pkalg/pkblob are acceptable */
}
xfree(pkalg);
xfree(pkblob);
}
}
/* XXX check if other auth methods are needed */
if (authenticated) {
/* turn off userauth */
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
packet_start(SSH2_MSG_USERAUTH_SUCCESS);
packet_send();
packet_write_wait();
log("userauth success for %s", user);
/* now we can break out */
userauth_success = 1;
} else {
packet_start(SSH2_MSG_USERAUTH_FAILURE);
packet_put_cstring("password");
packet_put_char(0); /* partial success */
packet_send();
packet_write_wait();
}
xfree(service);
xfree(user);
xfree(method);
}
void
do_authentication2()
{
dispatch_init(&protocol_error);
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
dispatch_run(DISPATCH_BLOCK, &userauth_success);
do_authenticated2();
}

7
auth.h
View File

@ -7,4 +7,11 @@ void do_authentication2(void);
struct passwd * struct passwd *
auth_get_user(void); 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 #endif

512
auth1.c Normal file
View File

@ -0,0 +1,512 @@
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*/
#include "includes.h"
RCSID("$OpenBSD: auth1.c,v 1.1 2000/04/26 21:28:32 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());
#ifdef WITH_AIXAUTHENTICATE
if (strncmp(get_authname(type),"password",
strlen(get_authname(type))) == 0)
loginfailed(pw->pw_name,get_canonical_hostname(),"ssh");
#endif /* WITH_AIXAUTHENTICATE */
/* 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;
#ifndef SKEY
(void)packet_read(&plen);
#else /* SKEY */
int type = packet_read(&plen);
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 = NULL, *password = NULL;
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);
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))
error("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);
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);
#ifdef USE_PAM
/* Do PAM auth with password */
authenticated = auth_pam_password(pw, password);
#else /* USE_PAM */
/* Try authentication with the password. */
authenticated = auth_password(pw, password);
#endif /* USE_PAM */
memset(password, 0, 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);
#ifdef USE_PAM
if (authenticated) {
if (!do_pam_account(pw->pw_name, client_user)) {
if (client_user != NULL) {
xfree(client_user);
client_user = NULL;
}
do_fake_authloop1(pw->pw_name);
}
return;
}
#else /* USE_PAM */
if (authenticated) {
return;
}
#endif /* USE_PAM */
if (client_user != NULL) {
xfree(client_user);
client_user = NULL;
}
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;
#ifdef WITH_AIXAUTHENTICATE
char *loginmsg;
#endif /* WITH_AIXAUTHENTICATE */
/* 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;
#ifdef USE_PAM
start_pam(pw);
#endif
/*
* 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 */
#ifdef USE_PAM
auth_pam_password(pw, "")) {
#else /* USE_PAM */
auth_password(pw, "")) {
#endif /* USE_PAM */
/* 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. */
#ifdef WITH_AIXAUTHENTICATE
loginsuccess(user,get_canonical_hostname(),"ssh",&loginmsg);
#endif /* WITH_AIXAUTHENTICATE */
packet_start(SSH_SMSG_SUCCESS);
packet_send();
packet_write_wait();
/* Perform session preparation. */
do_authenticated(pw);
}

459
auth2.c Normal file
View File

@ -0,0 +1,459 @@
/*
* 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.3 2000/04/27 15:23:02 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()
{
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());
}
#ifdef USE_PAM
if (authenticated && !do_pam_account(pw->pw_name, NULL))
authenticated = 0;
#endif /* USE_PAM */
/* XXX todo: check if multiple auth methods are needed */
if (authenticated == 1) {
authmsg = "Accepted";
/* 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) {
authmsg = "Failed";
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();
} else {
authmsg = "Postponed";
}
/* Raise logging level */
if (authenticated == 1||
attempt == AUTH_FAIL_LOG ||
strcmp(method, "password") == 0)
authlog = log;
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());
xfree(service);
xfree(user);
xfree(method);
}
int
ssh2_auth_none(struct passwd *pw)
{
packet_done();
#ifdef USE_PAM
return auth_pam_password(pw, "");
#else /* USE_PAM */
return auth_password(pw, "");
#endif /* USE_PAM */
}
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 &&
#ifdef USE_PAM
auth_pam_password(pw, password) == 1)
#else /* USE_PAM */
auth_password(pw, password) == 1)
#endif /* USE_PAM */
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.rsa_authentication == 0) {
debug("pubkey auth disabled");
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 ? */
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;
}
#ifdef USE_PAM
start_pam(pw);
#endif
copy = &authctxt->pw;
memset(copy, 0, sizeof(*copy));
copy->pw_name = xstrdup(pw->pw_name);
copy->pw_passwd = xstrdup(pw->pw_passwd);
copy->pw_uid = pw->pw_uid;
copy->pw_gid = pw->pw_gid;
copy->pw_dir = xstrdup(pw->pw_dir);
copy->pw_shell = xstrdup(pw->pw_shell);
authctxt->valid = 1;
} else {
if (strcmp(u, authctxt->user) != 0 ||
strcmp(s, authctxt->service) != 0) {
log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
u, s, authctxt->user, authctxt->service);
return NULL;
}
}
return auth_get_user();
}
/* 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

@ -15,14 +15,20 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: authfile.c,v 1.11 2000/04/16 02:31:49 damien Exp $"); RCSID("$Id: authfile.c,v 1.12 2000/04/29 13:57:10 damien Exp $");
#include <openssl/bn.h> #include <openssl/bn.h>
#include <openssl/dsa.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#include "xmalloc.h" #include "xmalloc.h"
#include "buffer.h" #include "buffer.h"
#include "bufaux.h" #include "bufaux.h"
#include "cipher.h" #include "cipher.h"
#include "ssh.h" #include "ssh.h"
#include "key.h"
/* Version identification string for identity files. */ /* Version identification string for identity files. */
#define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n" #define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n"
@ -35,8 +41,8 @@ RCSID("$Id: authfile.c,v 1.11 2000/04/16 02:31:49 damien Exp $");
*/ */
int int
save_private_key(const char *filename, const char *passphrase, save_private_key_rsa(const char *filename, const char *passphrase,
RSA *key, const char *comment) RSA *key, const char *comment)
{ {
Buffer buffer, encrypted; Buffer buffer, encrypted;
char buf[100], *cp; char buf[100], *cp;
@ -128,6 +134,63 @@ save_private_key(const char *filename, const char *passphrase,
return 1; 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 * 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 * 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 int
load_public_key(const char *filename, RSA * pub, load_public_key_rsa(const char *filename, RSA * pub, char **comment_return)
char **comment_return)
{ {
int fd, i; int fd, i;
off_t len; 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) { if (read(fd, cp, (size_t) len) != (size_t) len) {
debug("Read from key file %.200s failed: %.100s", filename, debug("Read from key file %.200s failed: %.100s", filename,
strerror(errno)); strerror(errno));
buffer_free(&buffer); buffer_free(&buffer);
close(fd); close(fd);
return 0; return 0;
@ -183,9 +245,13 @@ load_public_key(const char *filename, RSA * pub,
/* Read the public key from the buffer. */ /* Read the public key from the buffer. */
buffer_get_int(&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); 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); buffer_get_bignum(&buffer, pub->e);
if (comment_return) if (comment_return)
*comment_return = buffer_get_string(&buffer, NULL); *comment_return = buffer_get_string(&buffer, NULL);
@ -196,6 +262,20 @@ load_public_key(const char *filename, RSA * pub,
return 1; 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 * 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 * (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 int
load_private_key(const char *filename, const char *passphrase, load_private_key_rsa(int fd, const char *filename,
RSA * prv, char **comment_return) const char *passphrase, RSA * prv, char **comment_return)
{ {
int fd, i, check1, check2, cipher_type; int i, check1, check2, cipher_type;
off_t len; off_t len;
Buffer buffer, decrypted; Buffer buffer, decrypted;
char *cp; char *cp;
CipherContext cipher; CipherContext cipher;
BN_CTX *ctx; BN_CTX *ctx;
BIGNUM *aux; 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 && getuid() != 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); len = lseek(fd, (off_t) 0, SEEK_END);
lseek(fd, (off_t) 0, SEEK_SET); lseek(fd, (off_t) 0, SEEK_SET);
@ -309,7 +371,9 @@ load_private_key(const char *filename, const char *passphrase,
buffer_free(&decrypted); buffer_free(&decrypted);
fail: fail:
BN_clear_free(prv->n); BN_clear_free(prv->n);
prv->n = NULL;
BN_clear_free(prv->e); BN_clear_free(prv->e);
prv->e = NULL;
if (comment_return) if (comment_return)
xfree(*comment_return); xfree(*comment_return);
return 0; return 0;
@ -343,3 +407,87 @@ fail:
return 1; 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
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

@ -28,7 +28,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: compat.c,v 1.8 2000/04/16 01:18:42 damien Exp $"); RCSID("$Id: compat.c,v 1.9 2000/04/29 13:57:10 damien Exp $");
#include "ssh.h" #include "ssh.h"
#include "packet.h" #include "packet.h"
@ -44,7 +44,6 @@ enable_compat20(void)
{ {
verbose("Enabling compatibility mode for protocol 2.0"); verbose("Enabling compatibility mode for protocol 2.0");
compat20 = 1; compat20 = 1;
packet_set_ssh2_format();
} }
void void
enable_compat13(void) enable_compat13(void)

78
dsa.c
View File

@ -28,7 +28,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: dsa.c,v 1.4 2000/04/14 10:30:31 markus Exp $"); RCSID("$Id: dsa.c,v 1.5 2000/04/26 20:56:29 markus Exp $");
#include "ssh.h" #include "ssh.h"
#include "xmalloc.h" #include "xmalloc.h"
@ -47,13 +47,14 @@ RCSID("$Id: dsa.c,v 1.4 2000/04/14 10:30:31 markus Exp $");
#include <openssl/hmac.h> #include <openssl/hmac.h>
#include "kex.h" #include "kex.h"
#include "key.h" #include "key.h"
#include "uuencode.h"
#define INTBLOB_LEN 20 #define INTBLOB_LEN 20
#define SIGBLOB_LEN (2*INTBLOB_LEN) #define SIGBLOB_LEN (2*INTBLOB_LEN)
Key * Key *
dsa_serverkey_from_blob( dsa_key_from_blob(
char *serverhostkey, int serverhostkeylen) char *blob, int blen)
{ {
Buffer b; Buffer b;
char *ktype; char *ktype;
@ -61,14 +62,17 @@ dsa_serverkey_from_blob(
DSA *dsa; DSA *dsa;
Key *key; Key *key;
#ifdef DEBUG_DSS
dump_base64(blob, blen);
#endif
/* fetch & parse DSA/DSS pubkey */ /* fetch & parse DSA/DSS pubkey */
key = key_new(KEY_DSA); key = key_new(KEY_DSA);
dsa = key->dsa; dsa = key->dsa;
buffer_init(&b); buffer_init(&b);
buffer_append(&b, serverhostkey, serverhostkeylen); buffer_append(&b, blob, blen);
ktype = buffer_get_string(&b, NULL); ktype = buffer_get_string(&b, NULL);
if (strcmp(KEX_DSS, ktype) != 0) { if (strcmp(KEX_DSS, ktype) != 0) {
error("dsa_serverkey_from_blob: cannot handle type %s", ktype); error("dsa_key_from_blob: cannot handle type %s", ktype);
key_free(key); key_free(key);
return NULL; return NULL;
} }
@ -78,7 +82,7 @@ dsa_serverkey_from_blob(
buffer_get_bignum2(&b, dsa->pub_key); buffer_get_bignum2(&b, dsa->pub_key);
rlen = buffer_len(&b); rlen = buffer_len(&b);
if(rlen != 0) if(rlen != 0)
error("dsa_serverkey_from_blob: remaining bytes in serverhostkey %d", rlen); error("dsa_key_from_blob: remaining bytes in key blob %d", rlen);
buffer_free(&b); buffer_free(&b);
debug("keytype %s", ktype); debug("keytype %s", ktype);
@ -87,37 +91,8 @@ dsa_serverkey_from_blob(
#endif #endif
return key; return key;
} }
DSA *
dsa_load_private(char *filename)
{
DSA *dsa;
BIO *in;
in = BIO_new(BIO_s_file());
if (in == NULL)
fatal("BIO_new failed");
if (BIO_read_filename(in, filename) <= 0)
fatal("BIO_read failed %s: %s", filename, strerror(errno));
fprintf(stderr, "read DSA private key\n");
dsa = PEM_read_bio_DSAPrivateKey(in,NULL,NULL,NULL);
if (dsa == NULL)
fatal("PEM_read_bio_DSAPrivateKey failed %s", filename);
BIO_free(in);
return dsa;
}
Key *
dsa_get_serverkey(char *filename)
{
Key *k = key_new(KEY_EMPTY);
k->type = KEY_DSA;
k->dsa = dsa_load_private(filename);
#ifdef DEBUG_DSS
DSA_print_fp(stderr, dsa, 8);
#endif
return k;
}
int int
dsa_make_serverkey_blob(Key *key, unsigned char **blobp, unsigned int *lenp) dsa_make_key_blob(Key *key, unsigned char **blobp, unsigned int *lenp)
{ {
Buffer b; Buffer b;
int len; int len;
@ -146,7 +121,7 @@ int
dsa_sign( dsa_sign(
Key *key, Key *key,
unsigned char **sigp, int *lenp, unsigned char **sigp, int *lenp,
unsigned char *hash, int hlen) unsigned char *data, int datalen)
{ {
unsigned char *digest; unsigned char *digest;
unsigned char *ret; unsigned char *ret;
@ -165,10 +140,13 @@ dsa_sign(
} }
digest = xmalloc(evp_md->md_size); digest = xmalloc(evp_md->md_size);
EVP_DigestInit(&md, evp_md); EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, hash, hlen); EVP_DigestUpdate(&md, data, datalen);
EVP_DigestFinal(&md, digest, NULL); EVP_DigestFinal(&md, digest, NULL);
sig = DSA_do_sign(digest, evp_md->md_size, key->dsa); 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); rlen = BN_num_bytes(sig->r);
slen = BN_num_bytes(sig->s); slen = BN_num_bytes(sig->s);
@ -212,7 +190,7 @@ int
dsa_verify( dsa_verify(
Key *key, Key *key,
unsigned char *signature, int signaturelen, unsigned char *signature, int signaturelen,
unsigned char *hash, int hlen) unsigned char *data, int datalen)
{ {
Buffer b; Buffer b;
unsigned char *digest; unsigned char *digest;
@ -269,10 +247,10 @@ dsa_verify(
xfree(sigblob); xfree(sigblob);
} }
/* sha1 the signed data (== session_id == hash) */ /* sha1 the data */
digest = xmalloc(evp_md->md_size); digest = xmalloc(evp_md->md_size);
EVP_DigestInit(&md, evp_md); EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, hash, hlen); EVP_DigestUpdate(&md, data, datalen);
EVP_DigestFinal(&md, digest, NULL); EVP_DigestFinal(&md, digest, NULL);
ret = DSA_do_verify(digest, evp_md->md_size, sig, key->dsa); ret = DSA_do_verify(digest, evp_md->md_size, sig, key->dsa);
@ -296,3 +274,21 @@ dsa_verify(
debug("dsa_verify: signature %s", txt); debug("dsa_verify: signature %s", txt);
return ret; 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;
}

12
dsa.h
View File

@ -1,20 +1,22 @@
#ifndef DSA_H #ifndef DSA_H
#define DSA_H #define DSA_H
Key *dsa_serverkey_from_blob(char *serverhostkey, int serverhostkeylen); Key *dsa_key_from_blob(char *blob, int blen);
Key *dsa_get_serverkey(char *filename); int dsa_make_key_blob(Key *key, unsigned char **blobp, unsigned int *lenp);
int dsa_make_serverkey_blob(Key *key, unsigned char **blobp, unsigned int *lenp);
int int
dsa_sign( dsa_sign(
Key *key, Key *key,
unsigned char **sigp, int *lenp, unsigned char **sigp, int *lenp,
unsigned char *hash, int hlen); unsigned char *data, int datalen);
int int
dsa_verify( dsa_verify(
Key *key, Key *key,
unsigned char *signature, int signaturelen, unsigned char *signature, int signaturelen,
unsigned char *hash, int hlen); unsigned char *data, int datalen);
Key *
dsa_generate_key(unsigned int bits);
#endif #endif

View File

@ -14,7 +14,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: hostfile.c,v 1.16 2000/04/14 10:30:31 markus Exp $"); RCSID("$OpenBSD: hostfile.c,v 1.17 2000/04/26 20:56:29 markus Exp $");
#include "packet.h" #include "packet.h"
#include "match.h" #include "match.h"
@ -39,13 +39,8 @@ hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret)
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++) for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
; ;
/* Get number of bits. */ bits = key_read(ret, &cp);
if (*cp < '0' || *cp > '9') if (bits == 0)
return 0; /* Bad bit count... */
for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
bits = 10 * bits + *cp - '0';
if (!key_read(ret, bits, &cp))
return 0; return 0;
/* Skip trailing whitespace. */ /* Skip trailing whitespace. */
@ -182,24 +177,18 @@ add_host_to_hostfile(const char *filename, const char *host, Key *key)
{ {
FILE *f; FILE *f;
int success = 0; int success = 0;
if (key == NULL) if (key == NULL)
return 1; return 1; /* XXX ? */
/* Open the file for appending. */
f = fopen(filename, "a"); f = fopen(filename, "a");
if (!f) if (!f)
return 0; return 0;
fprintf(f, "%s ", host); fprintf(f, "%s ", host);
if (key_write(key, f)) { if (key_write(key, f)) {
fprintf(f, "\n");
success = 1; success = 1;
} else { } else {
error("add_host_to_hostfile: saving key failed"); error("add_host_to_hostfile: saving key in %s failed", filename);
} }
fprintf(f, "\n");
/* Close the file. */
fclose(f); fclose(f);
return success; return success;
} }

107
key.c
View File

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

3
key.h
View File

@ -18,6 +18,7 @@ void key_free(Key *k);
int key_equal(Key *a, Key *b); int key_equal(Key *a, Key *b);
char *key_fingerprint(Key *k); char *key_fingerprint(Key *k);
int key_write(Key *key, FILE *f); 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 #endif

96
radix.c
View File

@ -1,109 +1,15 @@
/* /*
* radix.c * 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> * Dug Song <dugsong@UMICH.EDU>
*/ */
#include "includes.h" #include "includes.h"
#include "uuencode.h"
#ifdef AFS #ifdef AFS
#include <krb.h> #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 char my_u_char;
typedef unsigned int my_u_int32_t; typedef unsigned int my_u_int32_t;
typedef unsigned short my_u_short; typedef unsigned short my_u_short;

View File

@ -14,7 +14,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: readconf.c,v 1.11 2000/04/16 01:18:44 damien Exp $"); RCSID("$Id: readconf.c,v 1.12 2000/04/29 13:57:11 damien Exp $");
#include "ssh.h" #include "ssh.h"
#include "cipher.h" #include "cipher.h"
@ -104,7 +104,8 @@ typedef enum {
oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication, oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oIdentityFile2,
oGlobalKnownHostsFile2, oUserKnownHostsFile2
} OpCodes; } OpCodes;
/* Textual representations of the tokens. */ /* Textual representations of the tokens. */
@ -131,6 +132,7 @@ static struct {
{ "fallbacktorsh", oFallBackToRsh }, { "fallbacktorsh", oFallBackToRsh },
{ "usersh", oUseRsh }, { "usersh", oUseRsh },
{ "identityfile", oIdentityFile }, { "identityfile", oIdentityFile },
{ "identityfile2", oIdentityFile2 },
{ "hostname", oHostName }, { "hostname", oHostName },
{ "proxycommand", oProxyCommand }, { "proxycommand", oProxyCommand },
{ "port", oPort }, { "port", oPort },
@ -145,6 +147,8 @@ static struct {
{ "rhostsrsaauthentication", oRhostsRSAAuthentication }, { "rhostsrsaauthentication", oRhostsRSAAuthentication },
{ "globalknownhostsfile", oGlobalKnownHostsFile }, { "globalknownhostsfile", oGlobalKnownHostsFile },
{ "userknownhostsfile", oUserKnownHostsFile }, { "userknownhostsfile", oUserKnownHostsFile },
{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
{ "userknownhostsfile2", oUserKnownHostsFile2 },
{ "connectionattempts", oConnectionAttempts }, { "connectionattempts", oConnectionAttempts },
{ "batchmode", oBatchMode }, { "batchmode", oBatchMode },
{ "checkhostip", oCheckHostIP }, { "checkhostip", oCheckHostIP },
@ -368,14 +372,22 @@ parse_flag:
goto parse_int; goto parse_int;
case oIdentityFile: case oIdentityFile:
case oIdentityFile2:
cp = strtok(NULL, WHITESPACE); cp = strtok(NULL, WHITESPACE);
if (!cp) if (!cp)
fatal("%.200s line %d: Missing argument.", filename, linenum); fatal("%.200s line %d: Missing argument.", filename, linenum);
if (*activep) { 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).", fatal("%.200s line %d: Too many identity files specified (max %d).",
filename, linenum, SSH_MAX_IDENTITY_FILES); 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; break;
@ -397,6 +409,14 @@ parse_string:
charptr = &options->user_hostfile; charptr = &options->user_hostfile;
goto parse_string; goto parse_string;
case oGlobalKnownHostsFile2:
charptr = &options->system_hostfile2;
goto parse_string;
case oUserKnownHostsFile2:
charptr = &options->user_hostfile2;
goto parse_string;
case oHostName: case oHostName:
charptr = &options->hostname; charptr = &options->hostname;
goto parse_string; goto parse_string;
@ -642,12 +662,15 @@ initialize_options(Options * options)
options->ciphers = NULL; options->ciphers = NULL;
options->protocol = SSH_PROTO_UNKNOWN; options->protocol = SSH_PROTO_UNKNOWN;
options->num_identity_files = 0; options->num_identity_files = 0;
options->num_identity_files2 = 0;
options->hostname = NULL; options->hostname = NULL;
options->proxy_command = NULL; options->proxy_command = NULL;
options->user = NULL; options->user = NULL;
options->escape_char = -1; options->escape_char = -1;
options->system_hostfile = NULL; options->system_hostfile = NULL;
options->user_hostfile = NULL; options->user_hostfile = NULL;
options->system_hostfile2 = NULL;
options->user_hostfile2 = NULL;
options->num_local_forwards = 0; options->num_local_forwards = 0;
options->num_remote_forwards = 0; options->num_remote_forwards = 0;
options->log_level = (LogLevel) - 1; options->log_level = (LogLevel) - 1;
@ -715,19 +738,31 @@ fill_default_options(Options * options)
if (options->cipher == -1) if (options->cipher == -1)
options->cipher = SSH_CIPHER_NOT_SET; options->cipher = SSH_CIPHER_NOT_SET;
if (options->protocol == SSH_PROTO_UNKNOWN) if (options->protocol == SSH_PROTO_UNKNOWN)
options->protocol = SSH_PROTO_1; options->protocol = SSH_PROTO_1|SSH_PROTO_2|SSH_PROTO_1_PREFERRED;
if (options->num_identity_files == 0) { if (options->num_identity_files == 0) {
options->identity_files[0] = options->identity_files[0] =
xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1); xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY); sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
options->num_identity_files = 1; options->num_identity_files = 1;
} }
#if 0
if (options->num_identity_files2 == 0) {
options->identity_files2[0] =
xmalloc(2 + strlen(SSH2_CLIENT_IDENTITY) + 1);
sprintf(options->identity_files2[0], "~/%.100s", SSH2_CLIENT_IDENTITY);
options->num_identity_files2 = 1;
}
#endif
if (options->escape_char == -1) if (options->escape_char == -1)
options->escape_char = '~'; options->escape_char = '~';
if (options->system_hostfile == NULL) if (options->system_hostfile == NULL)
options->system_hostfile = SSH_SYSTEM_HOSTFILE; options->system_hostfile = SSH_SYSTEM_HOSTFILE;
if (options->user_hostfile == NULL) if (options->user_hostfile == NULL)
options->user_hostfile = SSH_USER_HOSTFILE; 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) if (options->log_level == (LogLevel) - 1)
options->log_level = SYSLOG_LEVEL_INFO; options->log_level = SYSLOG_LEVEL_INFO;
/* options->proxy_command should not be set by default */ /* options->proxy_command should not be set by default */

View File

@ -13,7 +13,7 @@
* *
*/ */
/* RCSID("$Id: readconf.h,v 1.8 2000/04/16 01:18:44 damien Exp $"); */ /* RCSID("$Id: readconf.h,v 1.9 2000/04/29 13:57:11 damien Exp $"); */
#ifndef READCONF_H #ifndef READCONF_H
#define READCONF_H #define READCONF_H
@ -73,9 +73,13 @@ typedef struct {
char *system_hostfile;/* Path for /etc/ssh_known_hosts. */ char *system_hostfile;/* Path for /etc/ssh_known_hosts. */
char *user_hostfile; /* Path for $HOME/.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_files; /* Number of files for RSA identities. */
int num_identity_files2; /* DSA identities. */
char *identity_files[SSH_MAX_IDENTITY_FILES]; char *identity_files[SSH_MAX_IDENTITY_FILES];
char *identity_files2[SSH_MAX_IDENTITY_FILES];
/* Local TCP/IP forward requests. */ /* Local TCP/IP forward requests. */
int num_local_forwards; int num_local_forwards;

View File

@ -12,7 +12,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: servconf.c,v 1.12 2000/04/16 01:18:45 damien Exp $"); RCSID("$Id: servconf.c,v 1.13 2000/04/29 13:57:11 damien Exp $");
#include "ssh.h" #include "ssh.h"
#include "servconf.h" #include "servconf.h"
@ -143,7 +143,7 @@ fill_default_server_options(ServerOptions *options)
if (options->use_login == -1) if (options->use_login == -1)
options->use_login = 0; options->use_login = 0;
if (options->protocol == SSH_PROTO_UNKNOWN) if (options->protocol == SSH_PROTO_UNKNOWN)
options->protocol = SSH_PROTO_1; options->protocol = SSH_PROTO_1|SSH_PROTO_2;
} }
#define WHITESPACE " \t\r\n" #define WHITESPACE " \t\r\n"

View File

@ -733,7 +733,7 @@ server_input_channel_open(int type, int plen)
rwindow = packet_get_int(); rwindow = packet_get_int();
rmaxpack = packet_get_int(); rmaxpack = packet_get_int();
log("channel_input_open: ctype %s rchan %d win %d max %d", debug("channel_input_open: ctype %s rchan %d win %d max %d",
ctype, rchan, rwindow, rmaxpack); ctype, rchan, rwindow, rmaxpack);
if (strcmp(ctype, "session") == 0) { if (strcmp(ctype, "session") == 0) {

View File

@ -8,7 +8,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: session.c,v 1.5 2000/04/19 09:24:39 markus Exp $"); RCSID("$OpenBSD: session.c,v 1.6 2000/04/27 15:23:02 markus Exp $");
#include "xmalloc.h" #include "xmalloc.h"
#include "ssh.h" #include "ssh.h"
@ -1474,6 +1474,5 @@ do_authenticated2(void)
* authentication. * authentication.
*/ */
alarm(0); alarm(0);
log("do_authenticated2");
server_loop2(); server_loop2();
} }

View File

@ -7,13 +7,18 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: ssh-add.c,v 1.16 1999/12/06 00:47:29 damien Exp $"); RCSID("$Id: ssh-add.c,v 1.17 2000/04/29 13:57:12 damien Exp $");
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include "rsa.h" #include "rsa.h"
#include "ssh.h" #include "ssh.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "authfd.h" #include "authfd.h"
#include "fingerprint.h" #include "fingerprint.h"
#include "key.h"
#include "authfile.h"
#ifdef HAVE___PROGNAME #ifdef HAVE___PROGNAME
extern char *__progname; extern char *__progname;
@ -24,19 +29,19 @@ const char *__progname = "ssh-add";
void void
delete_file(AuthenticationConnection *ac, const char *filename) delete_file(AuthenticationConnection *ac, const char *filename)
{ {
RSA *key; Key *public;
char *comment; char *comment;
key = RSA_new(); public = key_new(KEY_RSA);
if (!load_public_key(filename, key, &comment)) { if (!load_public_key(filename, public, &comment)) {
printf("Bad key file %s: %s\n", filename, strerror(errno)); printf("Bad key file %s: %s\n", filename, strerror(errno));
return; return;
} }
if (ssh_remove_identity(ac, key)) if (ssh_remove_identity(ac, public->rsa))
fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment); fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
else else
fprintf(stderr, "Could not remove identity: %s\n", filename); fprintf(stderr, "Could not remove identity: %s\n", filename);
RSA_free(key); key_free(public);
xfree(comment); xfree(comment);
} }
@ -91,20 +96,19 @@ ssh_askpass(char *askpass, char *msg)
void void
add_file(AuthenticationConnection *ac, const char *filename) add_file(AuthenticationConnection *ac, const char *filename)
{ {
RSA *key; Key *public;
RSA *public_key; Key *private;
char *saved_comment, *comment, *askpass = NULL; char *saved_comment, *comment, *askpass = NULL;
char buf[1024], msg[1024]; char buf[1024], msg[1024];
int success; int success;
int interactive = isatty(STDIN_FILENO); int interactive = isatty(STDIN_FILENO);
key = RSA_new(); public = key_new(KEY_RSA);
public_key = RSA_new(); if (!load_public_key(filename, public, &saved_comment)) {
if (!load_public_key(filename, public_key, &saved_comment)) {
printf("Bad key file %s: %s\n", filename, strerror(errno)); printf("Bad key file %s: %s\n", filename, strerror(errno));
return; return;
} }
RSA_free(public_key); key_free(public);
if (!interactive && getenv("DISPLAY")) { if (!interactive && getenv("DISPLAY")) {
if (getenv(SSH_ASKPASS_ENV)) if (getenv(SSH_ASKPASS_ENV))
@ -114,7 +118,8 @@ add_file(AuthenticationConnection *ac, const char *filename)
} }
/* At first, try empty passphrase */ /* 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) { if (!success) {
printf("Need passphrase for %.200s\n", filename); printf("Need passphrase for %.200s\n", filename);
if (!interactive && askpass == NULL) { if (!interactive && askpass == NULL) {
@ -135,7 +140,7 @@ add_file(AuthenticationConnection *ac, const char *filename)
xfree(saved_comment); xfree(saved_comment);
return; return;
} }
success = load_private_key(filename, pass, key, &comment); success = load_private_key(filename, pass, private, &comment);
memset(pass, 0, strlen(pass)); memset(pass, 0, strlen(pass));
xfree(pass); xfree(pass);
if (success) if (success)
@ -145,11 +150,11 @@ add_file(AuthenticationConnection *ac, const char *filename)
} }
xfree(saved_comment); 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); fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
else else
fprintf(stderr, "Could not add identity: %s\n", filename); fprintf(stderr, "Could not add identity: %s\n", filename);
RSA_free(key); key_free(private);
xfree(comment); xfree(comment);
} }

View File

@ -9,7 +9,7 @@
.\" .\"
.\" Created: Sat Apr 22 23:55:14 1995 ylo .\" Created: Sat Apr 22 23:55:14 1995 ylo
.\" .\"
.\" $Id: ssh-keygen.1,v 1.12 2000/04/20 13:27:27 damien Exp $ .\" $Id: ssh-keygen.1,v 1.13 2000/04/29 13:57:12 damien Exp $
.\" .\"
.Dd September 25, 1999 .Dd September 25, 1999
.Dt SSH-KEYGEN 1 .Dt SSH-KEYGEN 1
@ -37,6 +37,8 @@
.Nm ssh-keygen .Nm ssh-keygen
.Fl l .Fl l
.Op Fl f Ar keyfile .Op Fl f Ar keyfile
.Nm ssh-keygen
.Fl R
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
generates and manages authentication keys for generates and manages authentication keys for
@ -112,6 +114,10 @@ Provides the new comment.
Provides the new passphrase. Provides the new passphrase.
.It Fl P Ar passphrase .It Fl P Ar passphrase
Provides the (old) 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.
.El .El
.Sh FILES .Sh FILES
.Bl -tag -width Ds .Bl -tag -width Ds

View File

@ -7,20 +7,23 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: ssh-keygen.c,v 1.13 2000/04/16 01:18:46 damien Exp $"); RCSID("$Id: ssh-keygen.c,v 1.14 2000/04/29 13:57:12 damien Exp $");
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include "rsa.h"
#include "ssh.h" #include "ssh.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "fingerprint.h" #include "fingerprint.h"
#include "key.h"
#include "rsa.h"
#include "dsa.h"
#include "authfile.h"
#include "uuencode.h"
/* Generated private key. */ /* Number of bits in the RSA/DSA key. This value can be changed on the command line. */
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. */
int bits = 1024; int bits = 1024;
/* /*
@ -53,6 +56,12 @@ char *identity_new_passphrase = NULL;
/* This is set to the new comment if given on the command line. */ /* This is set to the new comment if given on the command line. */
char *identity_comment = NULL; 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 */ /* argv0 */
#ifdef HAVE___PROGNAME #ifdef HAVE___PROGNAME
extern char *__progname; extern char *__progname;
@ -60,6 +69,8 @@ extern char *__progname;
const char *__progname = "ssh-keygen"; const char *__progname = "ssh-keygen";
#endif /* HAVE___PROGNAME */ #endif /* HAVE___PROGNAME */
char hostname[MAXHOSTNAMELEN];
void void
ask_filename(struct passwd *pw, const char *prompt) ask_filename(struct passwd *pw, const char *prompt)
{ {
@ -77,12 +88,140 @@ ask_filename(struct passwd *pw, const char *prompt)
have_identity = 1; 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;
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 (strncmp(line, "----", 4) == 0 ||
strstr(line, ": ") != NULL) {
fprintf(stderr, "ignore: %s", line);
continue;
}
if (!(p = strchr(line, '\n'))) {
fprintf(stderr, "input line too long.\n");
exit(1);
}
*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 void
do_fingerprint(struct passwd *pw) do_fingerprint(struct passwd *pw)
{ {
FILE *f; FILE *f;
BIGNUM *e, *n; BIGNUM *e, *n;
RSA *public_key; Key *public;
char *comment = NULL, *cp, *ep, line[16*1024]; char *comment = NULL, *cp, *ep, line[16*1024];
int i, skip = 0, num = 1, invalid = 1; int i, skip = 0, num = 1, invalid = 1;
unsigned int ignore; unsigned int ignore;
@ -94,17 +233,16 @@ do_fingerprint(struct passwd *pw)
perror(identity_file); perror(identity_file);
exit(1); exit(1);
} }
public = key_new(KEY_RSA);
public_key = RSA_new(); if (load_public_key(identity_file, public, &comment)) {
if (load_public_key(identity_file, public_key, &comment)) { printf("%d %s %s\n", BN_num_bits(public->rsa->n),
printf("%d %s %s\n", BN_num_bits(public_key->n), key_fingerprint(public), comment);
fingerprint(public_key->e, public_key->n), key_free(public);
comment);
RSA_free(public_key);
exit(0); exit(0);
} }
RSA_free(public_key); key_free(public);
/* XXX */
f = fopen(identity_file, "r"); f = fopen(identity_file, "r");
if (f != NULL) { if (f != NULL) {
n = BN_new(); n = BN_new();
@ -172,7 +310,9 @@ do_change_passphrase(struct passwd *pw)
char *comment; char *comment;
char *old_passphrase, *passphrase1, *passphrase2; char *old_passphrase, *passphrase1, *passphrase2;
struct stat st; struct stat st;
RSA *private_key; Key *private;
Key *public;
int type = dsa_mode ? KEY_DSA : KEY_RSA;
if (!have_identity) if (!have_identity)
ask_filename(pw, "Enter file in which the key is"); ask_filename(pw, "Enter file in which the key is");
@ -180,22 +320,26 @@ do_change_passphrase(struct passwd *pw)
perror(identity_file); perror(identity_file);
exit(1); exit(1);
} }
public_key = RSA_new();
if (!load_public_key(identity_file, public_key, NULL)) { if (type == KEY_RSA) {
printf("%s is not a valid key file.\n", identity_file); /* XXX this works currently only for RSA */
exit(1); 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. */ /* Try to load the file with empty passphrase. */
private_key = RSA_new(); private = key_new(type);
if (!load_private_key(identity_file, "", private_key, &comment)) { if (!load_private_key(identity_file, "", private, &comment)) {
if (identity_passphrase) if (identity_passphrase)
old_passphrase = xstrdup(identity_passphrase); old_passphrase = xstrdup(identity_passphrase);
else else
old_passphrase = read_passphrase("Enter old passphrase: ", 1); 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)); memset(old_passphrase, 0, strlen(old_passphrase));
xfree(old_passphrase); xfree(old_passphrase);
printf("Bad passphrase.\n"); printf("Bad passphrase.\n");
@ -230,19 +374,19 @@ do_change_passphrase(struct passwd *pw)
} }
/* Save the file using the new passphrase. */ /* 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", printf("Saving the key failed: %s: %s.\n",
identity_file, strerror(errno)); identity_file, strerror(errno));
memset(passphrase1, 0, strlen(passphrase1)); memset(passphrase1, 0, strlen(passphrase1));
xfree(passphrase1); xfree(passphrase1);
RSA_free(private_key); key_free(private);
xfree(comment); xfree(comment);
exit(1); exit(1);
} }
/* Destroy the passphrase and the copy of the key in memory. */ /* Destroy the passphrase and the copy of the key in memory. */
memset(passphrase1, 0, strlen(passphrase1)); memset(passphrase1, 0, strlen(passphrase1));
xfree(passphrase1); xfree(passphrase1);
RSA_free(private_key); /* Destroys contents */ key_free(private); /* Destroys contents */
xfree(comment); xfree(comment);
printf("Your identification has been saved with the new passphrase.\n"); printf("Your identification has been saved with the new passphrase.\n");
@ -256,11 +400,11 @@ void
do_change_comment(struct passwd *pw) do_change_comment(struct passwd *pw)
{ {
char new_comment[1024], *comment; char new_comment[1024], *comment;
RSA *private_key; Key *private;
Key *public;
char *passphrase; char *passphrase;
struct stat st; struct stat st;
FILE *f; FILE *f;
char *tmpbuf;
if (!have_identity) if (!have_identity)
ask_filename(pw, "Enter file in which the key is"); ask_filename(pw, "Enter file in which the key is");
@ -272,14 +416,14 @@ do_change_comment(struct passwd *pw)
* Try to load the public key from the file the verify that it is * Try to load the public key from the file the verify that it is
* readable and of the proper format. * readable and of the proper format.
*/ */
public_key = RSA_new(); public = key_new(KEY_RSA);
if (!load_public_key(identity_file, public_key, NULL)) { if (!load_public_key(identity_file, public, NULL)) {
printf("%s is not a valid key file.\n", identity_file); printf("%s is not a valid key file.\n", identity_file);
exit(1); 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(""); passphrase = xstrdup("");
else { else {
if (identity_passphrase) if (identity_passphrase)
@ -289,7 +433,7 @@ do_change_comment(struct passwd *pw)
else else
passphrase = read_passphrase("Enter passphrase: ", 1); passphrase = read_passphrase("Enter passphrase: ", 1);
/* Try to load using the passphrase. */ /* 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)); memset(passphrase, 0, strlen(passphrase));
xfree(passphrase); xfree(passphrase);
printf("Bad passphrase.\n"); printf("Bad passphrase.\n");
@ -305,7 +449,7 @@ do_change_comment(struct passwd *pw)
fflush(stdout); fflush(stdout);
if (!fgets(new_comment, sizeof(new_comment), stdin)) { if (!fgets(new_comment, sizeof(new_comment), stdin)) {
memset(passphrase, 0, strlen(passphrase)); memset(passphrase, 0, strlen(passphrase));
RSA_free(private_key); key_free(private);
exit(1); exit(1);
} }
if (strchr(new_comment, '\n')) if (strchr(new_comment, '\n'))
@ -313,18 +457,18 @@ do_change_comment(struct passwd *pw)
} }
/* Save the file using the new passphrase. */ /* 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", printf("Saving the key failed: %s: %s.\n",
identity_file, strerror(errno)); identity_file, strerror(errno));
memset(passphrase, 0, strlen(passphrase)); memset(passphrase, 0, strlen(passphrase));
xfree(passphrase); xfree(passphrase);
RSA_free(private_key); key_free(private);
xfree(comment); xfree(comment);
exit(1); exit(1);
} }
memset(passphrase, 0, strlen(passphrase)); memset(passphrase, 0, strlen(passphrase));
xfree(passphrase); xfree(passphrase);
RSA_free(private_key); key_free(private);
strlcat(identity_file, ".pub", sizeof(identity_file)); strlcat(identity_file, ".pub", sizeof(identity_file));
f = fopen(identity_file, "w"); f = fopen(identity_file, "w");
@ -332,13 +476,10 @@ do_change_comment(struct passwd *pw)
printf("Could not save your public key in %s\n", identity_file); printf("Could not save your public key in %s\n", identity_file);
exit(1); exit(1);
} }
fprintf(f, "%d ", BN_num_bits(public_key->n)); if (!key_write(public, f))
tmpbuf = BN_bn2dec(public_key->e); fprintf(stderr, "write key failed");
fprintf(f, "%s ", tmpbuf); key_free(public);
free(tmpbuf); fprintf(f, " %s\n", new_comment);
tmpbuf = BN_bn2dec(public_key->n);
fprintf(f, "%s %s\n", tmpbuf, new_comment);
free(tmpbuf);
fclose(f); fclose(f);
xfree(comment); xfree(comment);
@ -351,7 +492,7 @@ void
usage(void) usage(void)
{ {
printf("ssh-keygen version %s\n", SSH_VERSION); 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 [-b bits] [-p] [-c] [-l] [-x] [-X] [-y] [-f file] [-P pass] [-N new-pass] [-C comment]\n", __progname);
exit(1); exit(1);
} }
@ -363,29 +504,28 @@ main(int ac, char **av)
{ {
char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2; char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
struct passwd *pw; struct passwd *pw;
char *tmpbuf;
int opt; int opt;
struct stat st; struct stat st;
FILE *f; FILE *f;
char hostname[MAXHOSTNAMELEN]; Key *private;
Key *public;
extern int optind; extern int optind;
extern char *optarg; extern char *optarg;
/* check if RSA support exists */ OpenSSL_add_all_algorithms();
if (rsa_alive() == 0) {
fprintf(stderr,
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
__progname);
exit(1);
}
/* we need this for the home * directory. */ /* we need this for the home * directory. */
pw = getpwuid(getuid()); pw = getpwuid(getuid());
if (!pw) { if (!pw) {
printf("You don't exist, go away!\n"); printf("You don't exist, go away!\n");
exit(1); 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) { switch (opt) {
case 'b': case 'b':
bits = atoi(optarg); bits = atoi(optarg);
@ -428,6 +568,29 @@ main(int ac, char **av)
quiet = 1; quiet = 1;
break; 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 '?': case '?':
default: default:
usage(); usage();
@ -441,22 +604,44 @@ main(int ac, char **av)
printf("Can only have one of -p and -c.\n"); printf("Can only have one of -p and -c.\n");
usage(); 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) if (print_fingerprint)
do_fingerprint(pw); do_fingerprint(pw);
if (change_passphrase) if (change_passphrase)
do_change_passphrase(pw); do_change_passphrase(pw);
if (change_comment) if (change_comment)
do_change_comment(pw); 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(); arc4random_stir();
if (quiet) if (dsa_mode != 0) {
rsa_set_verbose(0); if (!quiet)
printf("Generating DSA parameter and key.\n");
/* Generate the rsa key pair. */ public = private = dsa_generate_key(bits);
private_key = RSA_new(); if (private == NULL) {
public_key = RSA_new(); fprintf(stderr, "dsa_generate_keys failed");
rsa_generate_key(private_key, public_key, bits); 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) if (!have_identity)
ask_filename(pw, "Enter file in which to save the key"); ask_filename(pw, "Enter file in which to save the key");
@ -509,17 +694,13 @@ passphrase_again:
strlcpy(comment, identity_comment, sizeof(comment)); strlcpy(comment, identity_comment, sizeof(comment));
} else { } else {
/* Create default commend field for the passphrase. */ /* Create default commend field for the passphrase. */
if (gethostname(hostname, sizeof(hostname)) < 0) {
perror("gethostname");
exit(1);
}
snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
} }
/* Save the key with the given passphrase and comment. */ /* 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", printf("Saving the key failed: %s: %s.\n",
identity_file, strerror(errno)); identity_file, strerror(errno));
memset(passphrase1, 0, strlen(passphrase1)); memset(passphrase1, 0, strlen(passphrase1));
xfree(passphrase1); xfree(passphrase1);
exit(1); exit(1);
@ -529,7 +710,9 @@ passphrase_again:
xfree(passphrase1); xfree(passphrase1);
/* Clear the private key and the random number generator. */ /* Clear the private key and the random number generator. */
RSA_free(private_key); if (private != public) {
key_free(private);
}
arc4random_stir(); arc4random_stir();
if (!quiet) if (!quiet)
@ -541,21 +724,18 @@ passphrase_again:
printf("Could not save your public key in %s\n", identity_file); printf("Could not save your public key in %s\n", identity_file);
exit(1); exit(1);
} }
fprintf(f, "%d ", BN_num_bits(public_key->n)); if (!key_write(public, f))
tmpbuf = BN_bn2dec(public_key->e); fprintf(stderr, "write key failed");
fprintf(f, "%s ", tmpbuf); fprintf(f, " %s\n", comment);
free(tmpbuf);
tmpbuf = BN_bn2dec(public_key->n);
fprintf(f, "%s %s\n", tmpbuf, comment);
free(tmpbuf);
fclose(f); fclose(f);
if (!quiet) { 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("The key fingerprint is:\n");
printf("%d %s %s\n", BN_num_bits(public_key->n), printf("%s %s\n", key_fingerprint(public), comment);
fingerprint(public_key->e, public_key->n),
comment);
} }
key_free(public);
exit(0); exit(0);
} }

65
ssh.c
View File

@ -11,7 +11,11 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$Id: ssh.c,v 1.26 2000/04/16 01:18:46 damien Exp $"); RCSID("$Id: ssh.c,v 1.27 2000/04/29 13:57:12 damien Exp $");
#include <openssl/evp.h>
#include <openssl/dsa.h>
#include <openssl/rsa.h>
#include "xmalloc.h" #include "xmalloc.h"
#include "ssh.h" #include "ssh.h"
@ -24,6 +28,8 @@ RCSID("$Id: ssh.c,v 1.26 2000/04/16 01:18:46 damien Exp $");
#include "ssh2.h" #include "ssh2.h"
#include "compat.h" #include "compat.h"
#include "channels.h" #include "channels.h"
#include "key.h"
#include "authfile.h"
#ifdef HAVE___PROGNAME #ifdef HAVE___PROGNAME
extern char *__progname; extern char *__progname;
@ -358,10 +364,16 @@ main(int ac, char **av)
} }
break; break;
case 'c': case 'c':
options.cipher = cipher_number(optarg); if (ciphers_valid(optarg)) {
if (options.cipher == -1) { /* SSH2 only */
fprintf(stderr, "Unknown cipher type '%s'\n", optarg); options.ciphers = xstrdup(optarg);
exit(1); } else {
/* SSH1 only */
options.cipher = cipher_number(optarg);
if (options.cipher == -1) {
fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
exit(1);
}
} }
break; break;
case 'p': case 'p':
@ -417,16 +429,11 @@ main(int ac, char **av)
if (!host) if (!host)
usage(); usage();
/* 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);
}
/* Initialize the command to execute on remote host. */ /* Initialize the command to execute on remote host. */
buffer_init(&command); buffer_init(&command);
OpenSSL_add_all_algorithms();
/* /*
* Save the command to execute on the remote host in a buffer. There * Save the command to execute on the remote host in a buffer. There
* is no limit on the length of the command, except by the maximum * is no limit on the length of the command, except by the maximum
@ -496,6 +503,20 @@ main(int ac, char **av)
/* reinit */ /* reinit */
log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0); 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) if (options.user == NULL)
options.user = xstrdup(pw->pw_name); options.user = xstrdup(pw->pw_name);
@ -562,9 +583,12 @@ main(int ac, char **av)
* authentication. This must be done before releasing extra * authentication. This must be done before releasing extra
* privileges, because the file is only readable by root. * 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(); 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; host_private_key_loaded = 1;
} }
/* /*
@ -610,15 +634,22 @@ main(int ac, char **av)
exit(1); exit(1);
} }
/* Expand ~ in options.identity_files. */ /* Expand ~ in options.identity_files. */
/* XXX mem-leaks */
for (i = 0; i < options.num_identity_files; i++) for (i = 0; i < options.num_identity_files; i++)
options.identity_files[i] = options.identity_files[i] =
tilde_expand_filename(options.identity_files[i], original_real_uid); 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. */ /* Expand ~ in known host file names. */
options.system_hostfile = tilde_expand_filename(options.system_hostfile, options.system_hostfile = tilde_expand_filename(options.system_hostfile,
original_real_uid); original_real_uid);
options.user_hostfile = tilde_expand_filename(options.user_hostfile, 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. */ /* Log into the remote system. This never returns if the login fails. */
ssh_login(host_private_key_loaded, host_private_key, ssh_login(host_private_key_loaded, host_private_key,

37
ssh.h
View File

@ -13,7 +13,7 @@
* *
*/ */
/* RCSID("$Id: ssh.h,v 1.34 2000/04/20 13:12:59 damien Exp $"); */ /* RCSID("$Id: ssh.h,v 1.35 2000/04/29 13:57:12 damien Exp $"); */
#ifndef SSH_H #ifndef SSH_H
#define SSH_H #define SSH_H
@ -88,6 +88,7 @@
* world-readable. * world-readable.
*/ */
#define SSH_SYSTEM_HOSTFILE ETCDIR "/ssh_known_hosts" #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 * Of these, ssh_host_key must be readable only by root, whereas ssh_config
@ -96,7 +97,7 @@
#define HOST_KEY_FILE ETCDIR "/ssh_host_key" #define HOST_KEY_FILE ETCDIR "/ssh_host_key"
#define SERVER_CONFIG_FILE ETCDIR "/sshd_config" #define SERVER_CONFIG_FILE ETCDIR "/sshd_config"
#define HOST_CONFIG_FILE ETCDIR "/ssh_config" #define HOST_CONFIG_FILE ETCDIR "/ssh_config"
#define DSA_KEY_FILE ETCDIR "/ssh_dsa_key" #define DSA_KEY_FILE ETCDIR "/ssh_host_dsa_key"
#ifndef SSH_PROGRAM #ifndef SSH_PROGRAM
#define SSH_PROGRAM "/usr/bin/ssh" #define SSH_PROGRAM "/usr/bin/ssh"
@ -128,6 +129,7 @@
* contain anything particularly secret. * contain anything particularly secret.
*/ */
#define SSH_USER_HOSTFILE "~/.ssh/known_hosts" #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 * Name of the default file containing client-side authentication key. This
@ -152,6 +154,7 @@
* running as root.) * running as root.)
*/ */
#define SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys" #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 * Per-user and system-wide ssh "rc" files. These files are executed with
@ -407,36 +410,6 @@ int auth_rsa_challenge_dialog(RSA *pk);
*/ */
char *read_passphrase(const char *prompt, int from_stdin); 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. -----------------------*/ /*------------ Definitions for logging. -----------------------*/

File diff suppressed because it is too large Load Diff

16
sshconnect.h Normal file
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

1020
sshconnect1.c Normal file

File diff suppressed because it is too large Load Diff

449
sshconnect2.c Normal file
View File

@ -0,0 +1,449 @@
/*
* 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.4 2000/04/27 17:54:01 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_ARCFOUR ||
options.cipher == SSH_CIPHER_3DES_CBC ||
options.cipher == SSH_CIPHER_CAST128_CBC ||
options.cipher == SSH_CIPHER_BLOWFISH_CBC) {
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
myproposal[PROPOSAL_ENC_ALGS_STOC] = cipher_name(options.cipher);
}
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)
{
char prompt[80];
char *password;
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;
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, 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);
/* generate signature */
dsa_sign(k, &signature, &slen, buffer_ptr(&b), buffer_len(&b));
key_free(k);
#ifdef DEBUG_DSS
buffer_dump(&b);
#endif
/* 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 ?? */
log("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.rsa_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");
}

221
sshd.c
View File

@ -14,7 +14,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: sshd.c,v 1.107 2000/04/19 07:05:50 deraadt Exp $"); RCSID("$OpenBSD: sshd.c,v 1.111 2000/04/27 08:01:28 markus Exp $");
#include "xmalloc.h" #include "xmalloc.h"
#include "rsa.h" #include "rsa.h"
@ -40,6 +40,7 @@ RCSID("$OpenBSD: sshd.c,v 1.107 2000/04/19 07:05:50 deraadt Exp $");
#include "auth.h" #include "auth.h"
#include "myproposal.h" #include "myproposal.h"
#include "authfile.h"
#ifdef LIBWRAP #ifdef LIBWRAP
#include <tcpd.h> #include <tcpd.h>
@ -112,8 +113,9 @@ char *server_version_string = NULL;
* not very useful. Currently, memory locking is not implemented. * not very useful. Currently, memory locking is not implemented.
*/ */
struct { struct {
RSA *private_key; /* Private part of server key. */ RSA *private_key; /* Private part of empheral server key. */
RSA *host_key; /* Private part of host key. */ RSA *host_key; /* Private part of host key. */
Key *dsa_host_key; /* Private DSA host key. */
} sensitive_data; } sensitive_data;
/* /*
@ -132,6 +134,10 @@ RSA *public_key;
/* session identifier, used by RSA-auth */ /* session identifier, used by RSA-auth */
unsigned char session_id[16]; unsigned char session_id[16];
/* same for ssh2 */
unsigned char *session_id2 = NULL;
int session_id2_len = 0;
/* Prototypes for various functions defined later in this file. */ /* Prototypes for various functions defined later in this file. */
void do_ssh1_kex(); void do_ssh1_kex();
void do_ssh2_kex(); void do_ssh2_kex();
@ -224,6 +230,7 @@ grace_alarm_handler(int sig)
* Thus there should be no concurrency control/asynchronous execution * Thus there should be no concurrency control/asynchronous execution
* problems. * problems.
*/ */
/* XXX do we really want this work to be done in a signal handler ? -m */
void void
key_regeneration_alarm(int sig) key_regeneration_alarm(int sig)
{ {
@ -344,6 +351,13 @@ sshd_exchange_identification(int sock_in, int sock_out)
mismatch = 0; mismatch = 0;
switch(remote_major) { switch(remote_major) {
case 1: case 1:
if (remote_minor == 99) {
if (options.protocol & SSH_PROTO_2)
enable_compat20();
else
mismatch = 1;
break;
}
if (!(options.protocol & SSH_PROTO_1)) { if (!(options.protocol & SSH_PROTO_1)) {
mismatch = 1; mismatch = 1;
break; break;
@ -355,12 +369,6 @@ sshd_exchange_identification(int sock_in, int sock_out)
/* note that this disables agent-forwarding */ /* note that this disables agent-forwarding */
enable_compat13(); enable_compat13();
} }
if (remote_minor == 99) {
if (options.protocol & SSH_PROTO_2)
enable_compat20();
else
mismatch = 1;
}
break; break;
case 2: case 2:
if (options.protocol & SSH_PROTO_2) { if (options.protocol & SSH_PROTO_2) {
@ -386,6 +394,20 @@ sshd_exchange_identification(int sock_in, int sock_out)
server_version_string, client_version_string); server_version_string, client_version_string);
fatal_cleanup(); fatal_cleanup();
} }
if (compat20)
packet_set_ssh2_format();
}
void
destroy_sensitive_data(void)
{
/* Destroy the private and public keys. They will no longer be needed. */
RSA_free(public_key);
RSA_free(sensitive_data.private_key);
RSA_free(sensitive_data.host_key);
if (sensitive_data.dsa_host_key != NULL)
key_free(sensitive_data.dsa_host_key);
} }
/* /*
@ -399,12 +421,11 @@ main(int ac, char **av)
int opt, sock_in = 0, sock_out = 0, newsock, i, fdsetsz, on = 1; int opt, sock_in = 0, sock_out = 0, newsock, i, fdsetsz, on = 1;
pid_t pid; pid_t pid;
socklen_t fromlen; socklen_t fromlen;
int silentrsa = 0; int silent = 0;
fd_set *fdset; fd_set *fdset;
struct sockaddr_storage from; struct sockaddr_storage from;
const char *remote_ip; const char *remote_ip;
int remote_port; int remote_port;
char *comment;
FILE *f; FILE *f;
struct linger linger; struct linger linger;
struct addrinfo *ai; struct addrinfo *ai;
@ -441,7 +462,7 @@ main(int ac, char **av)
inetd_flag = 1; inetd_flag = 1;
break; break;
case 'Q': case 'Q':
silentrsa = 1; silent = 1;
break; break;
case 'q': case 'q':
options.log_level = SYSLOG_LEVEL_QUIET; options.log_level = SYSLOG_LEVEL_QUIET;
@ -497,27 +518,14 @@ main(int ac, char **av)
log_init(av0, log_init(av0,
options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level, options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
options.log_facility == -1 ? SYSLOG_FACILITY_AUTH : options.log_facility, options.log_facility == -1 ? SYSLOG_FACILITY_AUTH : options.log_facility,
!inetd_flag); !silent && !inetd_flag);
/* check if RSA support exists */
if (rsa_alive() == 0) {
if (silentrsa == 0)
printf("sshd: no RSA support in libssl and libcrypto -- exiting. See ssl(8)\n");
log("no RSA support in libssl and libcrypto -- exiting. See ssl(8)");
exit(1);
}
/* Read server configuration options from the configuration file. */ /* Read server configuration options from the configuration file. */
read_server_config(&options, config_file_name); read_server_config(&options, config_file_name);
/* Fill in default values for those options not explicitly set. */ /* Fill in default values for those options not explicitly set. */
fill_default_server_options(&options); fill_default_server_options(&options);
/* Check certain values for sanity. */
if (options.server_key_bits < 512 ||
options.server_key_bits > 32768) {
fprintf(stderr, "Bad server key size.\n");
exit(1);
}
/* Check that there are no remaining arguments. */ /* Check that there are no remaining arguments. */
if (optind < ac) { if (optind < ac) {
fprintf(stderr, "Extra argument %s.\n", av[optind]); fprintf(stderr, "Extra argument %s.\n", av[optind]);
@ -526,26 +534,79 @@ main(int ac, char **av)
debug("sshd version %.100s", SSH_VERSION); debug("sshd version %.100s", SSH_VERSION);
sensitive_data.host_key = RSA_new(); sensitive_data.dsa_host_key = NULL;
errno = 0; sensitive_data.host_key = NULL;
/* Load the host key. It must have empty passphrase. */
if (!load_private_key(options.host_key_file, "", /* check if RSA support exists */
sensitive_data.host_key, &comment)) { if ((options.protocol & SSH_PROTO_1) &&
error("Could not load host key: %.200s: %.100s", rsa_alive() == 0) {
options.host_key_file, strerror(errno)); log("no RSA support in libssl and libcrypto. See ssl(8)");
log("Disabling protocol version 1");
options.protocol &= ~SSH_PROTO_1;
}
/* Load the RSA/DSA host key. It must have empty passphrase. */
if (options.protocol & SSH_PROTO_1) {
Key k;
sensitive_data.host_key = RSA_new();
k.type = KEY_RSA;
k.rsa = sensitive_data.host_key;
errno = 0;
if (!load_private_key(options.host_key_file, "", &k, NULL)) {
error("Could not load host key: %.200s: %.100s",
options.host_key_file, strerror(errno));
log("Disabling protocol version 1");
options.protocol &= ~SSH_PROTO_1;
}
k.rsa = NULL;
}
if (options.protocol & SSH_PROTO_2) {
sensitive_data.dsa_host_key = key_new(KEY_DSA);
if (!load_private_key(options.dsa_key_file, "", sensitive_data.dsa_host_key, NULL)) {
error("Could not load DSA host key: %.200s", options.dsa_key_file);
log("Disabling protocol version 2");
options.protocol &= ~SSH_PROTO_2;
}
}
if (! options.protocol & (SSH_PROTO_1|SSH_PROTO_2)) {
if (silent == 0)
fprintf(stderr, "sshd: no hostkeys available -- exiting.\n");
log("sshd: no hostkeys available -- exiting.\n");
exit(1); exit(1);
} }
xfree(comment);
/* Initialize the log (it is reinitialized below in case we /* Check certain values for sanity. */
forked). */ if (options.protocol & SSH_PROTO_1) {
if (options.server_key_bits < 512 ||
options.server_key_bits > 32768) {
fprintf(stderr, "Bad server key size.\n");
exit(1);
}
/*
* Check that server and host key lengths differ sufficiently. This
* is necessary to make double encryption work with rsaref. Oh, I
* hate software patents. I dont know if this can go? Niels
*/
if (options.server_key_bits >
BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED &&
options.server_key_bits <
BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {
options.server_key_bits =
BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED;
debug("Forcing server key to %d bits to make it differ from host key.",
options.server_key_bits);
}
}
/* Initialize the log (it is reinitialized below in case we forked). */
if (debug_flag && !inetd_flag) if (debug_flag && !inetd_flag)
log_stderr = 1; log_stderr = 1;
log_init(av0, options.log_level, options.log_facility, log_stderr); log_init(av0, options.log_level, options.log_facility, log_stderr);
/* If not in debugging mode, and not started from inetd, /*
disconnect from the controlling terminal, and fork. The * If not in debugging mode, and not started from inetd, disconnect
original process exits. */ * from the controlling terminal, and fork. The original process
* exits.
*/
if (!debug_flag && !inetd_flag) { if (!debug_flag && !inetd_flag) {
#ifdef TIOCNOTTY #ifdef TIOCNOTTY
int fd; int fd;
@ -565,18 +626,6 @@ main(int ac, char **av)
/* Reinitialize the log (because of the fork above). */ /* Reinitialize the log (because of the fork above). */
log_init(av0, options.log_level, options.log_facility, log_stderr); log_init(av0, options.log_level, options.log_facility, log_stderr);
/* Check that server and host key lengths differ sufficiently.
This is necessary to make double encryption work with rsaref.
Oh, I hate software patents. I dont know if this can go? Niels */
if (options.server_key_bits >
BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED &&
options.server_key_bits <
BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {
options.server_key_bits =
BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED;
debug("Forcing server key to %d bits to make it differ from host key.",
options.server_key_bits);
}
/* Do not display messages to stdout in RSA code. */ /* Do not display messages to stdout in RSA code. */
rsa_set_verbose(0); rsa_set_verbose(0);
@ -594,20 +643,22 @@ main(int ac, char **av)
s2 = dup(s1); s2 = dup(s1);
sock_in = dup(0); sock_in = dup(0);
sock_out = dup(1); sock_out = dup(1);
/* We intentionally do not close the descriptors 0, 1, and 2 /*
as our code for setting the descriptors won\'t work * We intentionally do not close the descriptors 0, 1, and 2
if ttyfd happens to be one of those. */ * as our code for setting the descriptors won\'t work if
* ttyfd happens to be one of those.
*/
debug("inetd sockets after dupping: %d, %d", sock_in, sock_out); debug("inetd sockets after dupping: %d, %d", sock_in, sock_out);
public_key = RSA_new(); if (options.protocol & SSH_PROTO_1) {
sensitive_data.private_key = RSA_new(); public_key = RSA_new();
sensitive_data.private_key = RSA_new();
/* XXX check options.protocol */ log("Generating %d bit RSA key.", options.server_key_bits);
log("Generating %d bit RSA key.", options.server_key_bits); rsa_generate_key(sensitive_data.private_key, public_key,
rsa_generate_key(sensitive_data.private_key, public_key, options.server_key_bits);
options.server_key_bits); arc4random_stir();
arc4random_stir(); log("RSA key generation complete.");
log("RSA key generation complete."); }
} else { } else {
for (ai = options.listen_addrs; ai; ai = ai->ai_next) { for (ai = options.listen_addrs; ai; ai = ai->ai_next) {
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
@ -684,19 +735,20 @@ main(int ac, char **av)
fclose(f); fclose(f);
} }
} }
if (options.protocol & SSH_PROTO_1) {
public_key = RSA_new();
sensitive_data.private_key = RSA_new();
public_key = RSA_new(); log("Generating %d bit RSA key.", options.server_key_bits);
sensitive_data.private_key = RSA_new(); rsa_generate_key(sensitive_data.private_key, public_key,
options.server_key_bits);
arc4random_stir();
log("RSA key generation complete.");
log("Generating %d bit RSA key.", options.server_key_bits); /* Schedule server key regeneration alarm. */
rsa_generate_key(sensitive_data.private_key, public_key, signal(SIGALRM, key_regeneration_alarm);
options.server_key_bits); alarm(options.key_regeneration_time);
arc4random_stir(); }
log("RSA key generation complete.");
/* Schedule server key regeneration alarm. */
signal(SIGALRM, key_regeneration_alarm);
alarm(options.key_regeneration_time);
/* Arrange to restart on SIGHUP. The handler needs listen_sock. */ /* Arrange to restart on SIGHUP. The handler needs listen_sock. */
signal(SIGHUP, sighup_handler); signal(SIGHUP, sighup_handler);
@ -1069,9 +1121,7 @@ do_ssh1_kex()
sensitive_data.private_key->n); sensitive_data.private_key->n);
/* Destroy the private and public keys. They will no longer be needed. */ /* Destroy the private and public keys. They will no longer be needed. */
RSA_free(public_key); destroy_sensitive_data();
RSA_free(sensitive_data.private_key);
RSA_free(sensitive_data.host_key);
/* /*
* Extract session key from the decrypted integer. The key is in the * Extract session key from the decrypted integer. The key is in the
@ -1130,7 +1180,6 @@ do_ssh2_kex()
unsigned char *kbuf; unsigned char *kbuf;
unsigned char *hash; unsigned char *hash;
Kex *kex; Kex *kex;
Key *server_host_key;
char *cprop[PROPOSAL_MAX]; char *cprop[PROPOSAL_MAX];
char *sprop[PROPOSAL_MAX]; char *sprop[PROPOSAL_MAX];
@ -1231,8 +1280,8 @@ do_ssh2_kex()
memset(kbuf, 0, klen); memset(kbuf, 0, klen);
xfree(kbuf); xfree(kbuf);
server_host_key = dsa_get_serverkey(options.dsa_key_file); /* XXX precompute? */
dsa_make_serverkey_blob(server_host_key, &server_host_key_blob, &sbloblen); dsa_make_key_blob(sensitive_data.dsa_host_key, &server_host_key_blob, &sbloblen);
/* calc H */ /* XXX depends on 'kex' */ /* calc H */ /* XXX depends on 'kex' */
hash = kex_hash( hash = kex_hash(
@ -1255,10 +1304,17 @@ do_ssh2_kex()
fprintf(stderr, "%02x", (hash[i])&0xff); fprintf(stderr, "%02x", (hash[i])&0xff);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
#endif #endif
/* save session id := H */
/* XXX hashlen depends on KEX */
session_id2_len = 20;
session_id2 = xmalloc(session_id2_len);
memcpy(session_id2, hash, session_id2_len);
/* sign H */ /* sign H */
dsa_sign(server_host_key, &signature, &slen, hash, 20); /* XXX hashlen depends on KEX */
/* hashlen depends on KEX */ dsa_sign(sensitive_data.dsa_host_key, &signature, &slen, hash, 20);
key_free(server_host_key);
destroy_sensitive_data();
/* send server hostkey, DH pubkey 'f' and singed H */ /* send server hostkey, DH pubkey 'f' and singed H */
packet_start(SSH2_MSG_KEXDH_REPLY); packet_start(SSH2_MSG_KEXDH_REPLY);
@ -1267,6 +1323,7 @@ do_ssh2_kex()
packet_put_string((char *)signature, slen); packet_put_string((char *)signature, slen);
packet_send(); packet_send();
xfree(signature); xfree(signature);
xfree(server_host_key_blob);
packet_write_wait(); packet_write_wait();
kex_derive_keys(kex, hash, shared_secret); kex_derive_keys(kex, hash, shared_secret);

120
uuencode.c Normal file
View File

@ -0,0 +1,120 @@
/*
* 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 "xmalloc.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] = '=';
} else if (i == nbytes) {
*(outptr++) = '=';
}
*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);
}
void
dump_base64(FILE *fp, unsigned char *data, int len)
{
unsigned char *buf = xmalloc(2*len);
int i, n;
n = uuencode(data, len, buf);
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);
}

6
uuencode.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef UUENCODE_H
#define UUENCODE_H
int uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded);
int uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize);
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.0"